Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS> type in the chain from the given type that contains the given
* field or null if it is not found anywhere.
*/
T getTypeWithProperty(String field, T type);
/**
* Returns the type of the instance of which this is the prototype or null
* if this is not a function prototype.
*/
T getInstanceFromPrototype(T type);
/**
* Records that this property could be referenced from any interface that
* this type, or any type in its superclass chain, implements.
*/
void recordInterfaces(T type, T relatedType,
DisambiguateProperties<T>.Property p);
}
/** Implementation of TypeSystem using JSTypes. */
private static class JSTypeSystem implements TypeSystem<JSType> {
private final Set<JSType> invalidatingTypes;
private JSTypeRegistry registry;
public JSTypeSystem(AbstractCompiler compiler) {
registry = compiler.getTypeRegistry();
invalidatingTypes = Sets.newHashSet(
registry.getNativeType(JSTypeNative.ALL_TYPE),
registry.getNativeType(JSTypeNative.NO_OBJECT_TYPE),
registry.getNativeType(JSTypeNative.NO_TYPE),
registry.getNativeType(JSTypeNative.FUNCTION_PROTOTYPE),
registry.getNativeType(JSTypeNative.OBJECT_PROTOTYPE),
registry.getNativeType(JSTypeNative.TOP_LEVEL_PROTOTYPE),
registry.getNativeType(JSTypeNative.UNKNOWN_TYPE));
}
@Override public void addInvalidatingType(JSType type) {
checkState(!type.isUnionType());
invalidatingTypes.add(type);
}
@Override public StaticScope<JSType> getRootScope() { return null; }
@Override public StaticScope<JSType> getFunctionScope(Node node) {
return null;
}
@Override public JSType getType(
StaticScope<JSType> scope, Node node, String prop) {
if (node.getJSType() == null) {
return registry.getNativeType(JSTypeNative.UNKNOWN_TYPE);
}
return node.getJSType();
}
@Override public boolean isInvalidatingType(JSType type) {
if (type == null || invalidatingTypes.contains(type) ||
(type.isNamedType
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>() && type.isUnknownType())) {
return true;
}
ObjectType objType = ObjectType.cast(type);
return objType != null && !objType.hasReferenceName();
}
@Override public ImmutableSet<JSType> getTypesToSkipForType(JSType type) {
type = type.restrictByNotNullOrUndefined();
if (type instanceof UnionType) {
Set<JSType> types = Sets.newHashSet(type);
for (JSType alt : ((UnionType) type).getAlternates()) {
types.addAll(getTypesToSkipForTypeNonUnion(type));
}
return ImmutableSet.copyOf(types);
}
return ImmutableSet.copyOf(getTypesToSkipForTypeNonUnion(type));
}
private Set<JSType> getTypesToSkipForTypeNonUnion(JSType type) {
Set<JSType> types = Sets.newHashSet();
JSType skipType = type;
while (skipType != null) {
types.add(skipType);
ObjectType objSkipType = skipType.toObjectType();
if (objSkipType != null) {
skipType = objSkipType.getImplicitPrototype();
} else {
break;
}
}
return types;
}
@Override public boolean isTypeToSkip(JSType type) {
return type.isEnumType() || (type.autoboxesTo() != null);
}
@Override public JSType restrictByNotNullOrUndefined(JSType type) {
return type.restrictByNotNullOrUndefined();
}
@Override public Iterable<JSType> getTypeAlternatives(JSType type) {
if (type.isUnionType()) {
return ((UnionType) type).getAlternates();
} else {
ObjectType objType = type.toObjectType();
if (objType != null &&
objType.getConstructor() != null &&
objType.getConstructor().isInterface()) {
List<JSType> list = Lists.newArrayList();
for (FunctionType impl
: registry.getDirectImplementors(objType)) {
list.add(impl.getInstanceType());
}
return list;
} else {
return null;
}
}
}
@Override public ObjectType getTypeWithProperty(String field, JSType type) {
if (!(type instanceof ObjectType)) {
if (
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>(condition, blindScope, NE);
} else {
return caseEquality(condition, blindScope, EQ);
}
case Token.SHEQ:
if (outcome) {
return caseEquality(condition, blindScope, SHEQ);
} else {
return caseEquality(condition, blindScope, SHNE);
}
case Token.SHNE:
if (outcome) {
return caseEquality(condition, blindScope, SHNE);
} else {
return caseEquality(condition, blindScope, SHEQ);
}
case Token.NAME:
case Token.GETPROP:
return caseNameOrGetProp(condition, blindScope, outcome);
case Token.ASSIGN:
return firstPreciserScopeKnowingConditionOutcome(
condition.getFirstChild(),
firstPreciserScopeKnowingConditionOutcome(
condition.getFirstChild().getNext(), blindScope, outcome),
outcome);
case Token.NOT:
return firstPreciserScopeKnowingConditionOutcome(
condition.getFirstChild(), blindScope, !outcome);
case Token.LE:
case Token.LT:
case Token.GE:
case Token.GT:
if (outcome) {
return caseEquality(condition, blindScope, INEQ);
}
break;
case Token.INSTANCEOF:
return caseInstanceOf(
condition.getFirstChild(), condition.getLastChild(), blindScope,
outcome);
case Token.IN:
if (outcome && condition.getFirstChild().getType() == Token.STRING) {
return caseIn(condition.getLastChild(),
condition.getFirstChild().getString(), blindScope);
}
break;
case Token.CASE:
Node left =
condition.getParent().getFirstChild(); // the switch condition
Node right = condition.getFirstChild();
if (outcome) {
return caseEquality(left, right, blindScope, SHEQ);
} else {
return caseEquality(left, right, blindScope, SHNE);
}
}
return nextPreciserScopeKnowingConditionOutcome(
condition, blindScope, outcome);
}
private FlowScope caseEquality(Node condition, FlowScope blindScope,
Function<TypePair, TypePair> merging) {
return caseEquality(condition.getFirstChild(), condition.getLastChild(),
blindScope, merging);
}
private FlowScope caseEquality
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>/*
* Copyright 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.javascript.jscomp.parsing;
import com.google.common.collect.ImmutableMap;
import com.google.javascript.rhino.jstype.JSTypeRegistry;
import java.util.Map;
import java.util.Set;
/**
* Configuration for the AST factory. Should be shared across AST creation
* for all files of a compilation process.
*
*
*/
public class Config {
/**
* Central registry for type info.
*/
final JSTypeRegistry registry;
/**
* Whether to parse the descriptions of jsdoc comments.
*/
final boolean parseJsDocDocumentation;
/**
* Whether we're in ide mode.
*/
final boolean isIdeMode;
/**
* Recognized JSDoc annotations, mapped from their name to their internal
* representation.
*/
final Map<String, Annotation> annotationNames;
/**
* Annotation names.
*/
Config(JSTypeRegistry registry, Set<String> annotationWhitelist,
boolean isIdeMode) {
this.registry = registry;
this.annotationNames = buildAnnotationNames(annotationWhitelist);
this.parseJsDocDocumentation = isIdeMode;
this.isIdeMode = isIdeMode;
}
/**
* Create the annotation names from the user-specified
* annotation whitelist.
*/
private static Map<String, Annotation> buildAnnotationNames(
Set<String> annotationWhitelist) {
ImmutableMap.Builder<String, Annotation> annotationBuilder =
ImmutableMap.builder();
annotationBuilder.putAll(Annotation.recognizedAnnotations);
for (String unrecognizedAnnotation : annotationWhitelist) {
if (!Annotation.recognizedAnnotations.containsKey
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>/*
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1997-1999
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Bob Jervis
* Google Inc.
*
* Alternatively, the contents of this file may be used under the terms of
* the GNU General Public License Version 2 or later (the "GPL"), in which
* case the provisions of the GPL are applicable instead of those above. If
* you wish to allow use of your version of this file only under the terms of
* the GPL and not to allow others to use your version of this file under the
* MPL, indicate your decision by deleting the provisions above and replacing
* them with the notice and other provisions required by the GPL. If you do
* not delete the provisions above, a recipient may use your version of this
* file under either the MPL or the GPL.
*
* ***** END LICENSE BLOCK ***** */
/**
* For functions with function(this: T, ...) and T as arguments, type inference
* will set the type of this on a function literal argument to the actual type
* of T.
*
*
*/
package com.google.javascript.rhino.jstype;
public class TemplateType extends ProxyObjectType {
private static final long serialVersionUID = 1L;
private final String name;
TemplateType(JSTypeRegistry registry, String name) {
super(
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>registry, registry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE));
this.name = name;
}
@Override
public String getReferenceName() {
return name;
}
@Override
public String toString() {
return name;
}
@Override
public boolean isTemplateType() {
return true;
}
}
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>/*
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1997-1999
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Bob Jervis
* Google Inc.
*
* Alternatively, the contents of this file may be used under the terms of
* the GNU General Public License Version 2 or later (the "GPL"), in which
* case the provisions of the GPL are applicable instead of those above. If
* you wish to allow use of your version of this file only under the terms of
* the GPL and not to allow others to use your version of this file under the
* MPL, indicate your decision by deleting the provisions above and replacing
* them with the notice and other provisions required by the GPL. If you do
* not delete the provisions above, a recipient may use your version of this
* file under either the MPL or the GPL.
*
* ***** END LICENSE BLOCK ***** */
package com.google.javascript.rhino.jstype;
import static com.google.javascript.rhino.jstype.TernaryValue.FALSE;
import static com.google.javascript.rhino.jstype.TernaryValue.UNKNOWN;
/**
* Boolean type.
*
*/
public class BooleanType extends ValueType {
private static final long serialVersionUID = 1L;
BooleanType(JSTypeRegistry registry) {
super(registry);
}
@
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>Graph.Branch;
import com.google.javascript.jscomp.Scope.Var;
import com.google.javascript.jscomp.graph.DiGraph.DiGraphEdge;
import com.google.javascript.rhino.JSDocInfo;
import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.Token;
import com.google.javascript.rhino.jstype.BooleanLiteralSet;
import com.google.javascript.rhino.jstype.FunctionType;
import com.google.javascript.rhino.jstype.JSType;
import com.google.javascript.rhino.jstype.JSTypeNative;
import com.google.javascript.rhino.jstype.JSTypeRegistry;
import com.google.javascript.rhino.jstype.ObjectType;
import com.google.javascript.rhino.jstype.StaticSlot;
import com.google.javascript.rhino.jstype.UnionType;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
/**
* Type inference within a script node or a function body, using the data-flow
* analysis framework.
*
*
*/
class TypeInference
extends DataFlowAnalysis.BranchedForwardDataFlowAnalysis<Node, FlowScope> {
static final DiagnosticType TEMPLATE_TYPE_NOT_OBJECT_TYPE =
DiagnosticType.error(
"JSC_TEMPLATE_TYPE_NOT_OBJECT_TYPE",
"The template type must be an object type");
static final DiagnosticType TEMPLATE_TYPE_OF_THIS_EXPECTED =
DiagnosticType.error(
"JSC_TEMPLATE_TYPE_OF_THIS_EXPECTED",
"A function type with the template type as the type of this must be a " +
"parameter type");
private final AbstractCompiler compiler;
private final JSTypeRegistry registry;
private final ReverseAbstractInterpreter reverseInterpreter;
private final Scope syntacticScope;
private final FlowScope functionScope;
private final FlowScope bottomScope;
/**
* Local variables that do not belong to this scope, but are assigned
* in this scope.
*/
private final Multimap<Scope, Var> assignedOuterLocalVars =
HashMultimap.create();
/**
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS> * Vars that we should not map out type flow for.
*/
private final Set<String> unflowableVarNames = Sets.newHashSet();
TypeInference(AbstractCompiler compiler, ControlFlowGraph<Node> cfg,
ReverseAbstractInterpreter reverseInterpreter,
Scope functionScope) {
this(compiler, cfg, reverseInterpreter, functionScope,
ImmutableSet.<Var>of());
}
/**
* @param unflowableVars Do not do infer flow on the types of these vars.
*/
// TODO(nicksantos): Create a builder for this class.
TypeInference(AbstractCompiler compiler, ControlFlowGraph<Node> cfg,
ReverseAbstractInterpreter reverseInterpreter,
Scope functionScope, Collection<Var> unflowableVars) {
super(cfg, new LinkedFlowScope.FlowScopeJoinOp());
this.compiler = compiler;
this.registry = compiler.getTypeRegistry();
this.reverseInterpreter = reverseInterpreter;
this.syntacticScope = functionScope;
this.functionScope = LinkedFlowScope.createEntryLattice(functionScope);
for (Var unflowableVar : unflowableVars) {
String name = unflowableVar.getName();
if (functionScope.getVar(name) == unflowableVar) {
this.unflowableVarNames.add(name);
}
}
Iterator<Var> varIt = functionScope.getVars();
while (varIt.hasNext()) {
Var var = varIt.next();
if (this.unflowableVarNames.contains(var.getName())) {
continue;
}
// For each local variable declared with the VAR keyword, the entry
// type is VOID.
if (var.getParentNode() != null &&
var.getType() == null && // no declared type
var.getParentNode().getType() == Token.VAR &&
!var.isExtern()) {
this.functionScope.inferSlotType(
var.getName(), getNativeType(VOID_TYPE));
}
}
this.bottomScope = LinkedFlowScope.createEntryLattice(
new Scope(functionScope.getRootNode(), functionScope.getTypeOfThis()));
}
@Override
FlowScope createInitialEstimateLattice() {
return bottomScope;
}
@Override
FlowScope createEntryLattice() {
return functionScope
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS> Token.ASSIGN_BITOR:
case Token.ASSIGN_MUL:
case Token.ASSIGN_SUB:
case Token.DIV:
case Token.MOD:
case Token.BITAND:
case Token.BITXOR:
case Token.BITOR:
case Token.MUL:
case Token.SUB:
case Token.DEC:
case Token.INC:
case Token.BITNOT:
case Token.NUMBER:
scope = traverseChildren(n, scope);
n.setJSType(getNativeType(NUMBER_TYPE));
break;
case Token.LP:
case Token.GET_REF:
scope = traverse(n.getFirstChild(), scope);
n.setJSType(getJSType(n.getFirstChild()));
break;
case Token.COMMA:
scope = traverseChildren(n, scope);
n.setJSType(getJSType(n.getLastChild()));
break;
case Token.STRING:
case Token.TYPEOF:
scope = traverseChildren(n, scope);
n.setJSType(getNativeType(STRING_TYPE));
break;
case Token.LT:
case Token.LE:
case Token.GT:
case Token.GE:
case Token.NOT:
case Token.EQ:
case Token.NE:
case Token.SHEQ:
case Token.SHNE:
case Token.INSTANCEOF:
case Token.IN:
case Token.TRUE:
case Token.FALSE:
scope = traverseChildren(n, scope);
n.setJSType(getNativeType(BOOLEAN_TYPE));
break;
case Token.GETELEM:
scope = traverseGetElem(n, scope);
break;
case Token.EXPR_RESULT:
scope = traverseChildren(n, scope);
if (n.getFirstChild().getType() == Token.GETPROP) {
ensurePropertyDeclared(n.getFirstChild());
}
break;
case Token.SWITCH:
scope = traverse(n.getFirstChild(), scope);
break;
case Token.VAR:
case Token.RETURN:
case Token.THROW:
scope = traverseChildren(n, scope);
break;
case Token.CATCH:
scope = traverseCatch(n, scope);
break;
}
if (n.getType() != Token.FUNCTION) {
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS> inferred type.
// 2) If this isn't an instance object, define it.
// 3) If the property of an object is being assigned in the constructor,
// define it.
// 4) If this is a stub, define it.
// 5) Otherwise, do not define the type, but declare it in the registry
// so that we can use it for missing property checks.
if (objectType.hasProperty(propName) ||
!objectType.isInstanceType()) {
if ("prototype".equals(propName)) {
objectType.defineDeclaredProperty(propName, rightType, false);
} else {
objectType.defineInferredProperty(propName, rightType, false);
}
} else {
if (getprop.getFirstChild().getType() == Token.THIS &&
getJSType(syntacticScope.getRootNode()).isConstructor()) {
objectType.defineInferredProperty(propName, rightType, false);
} else {
registry.registerPropertyOnType(propName, objectType);
}
}
}
}
}
/**
* Defines a declared property if it has not been defined yet.
*
* This handles the case where a property is declared on an object where
* the object type is inferred, and so the object type will not
* be known in {@code TypedScopeCreator}.
*/
private void ensurePropertyDeclared(Node getprop) {
ObjectType ownerType = ObjectType.cast(
getJSType(getprop.getFirstChild()).restrictByNotNullOrUndefined());
if (ownerType != null) {
ensurePropertyDeclaredHelper(getprop, ownerType);
}
}
/**
* Declares a property on its owner, if necessary.
* @return True if a property was declared.
*/
private boolean ensurePropertyDeclaredHelper(
Node getprop, ObjectType objectType) {
String propName = getprop.getLastChild().getString();
String qName = getprop.getQualifiedName();
if (qName != null) {
Var var = syntacticScope.getVar(qName);
if (var != null && !var.isTypeInferred()) {
// Handle normal declarations that could not be addressed earlier.
if (propName.equals("prototype") ||
// Handle prototype declarations that could not be
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS> addressed earlier.
(!objectType.hasOwnProperty(propName) &&
(!objectType.isInstanceType() ||
(var.isExtern() && !objectType.isNativeObjectType())))) {
return objectType.defineDeclaredProperty(
propName, var.getType(), var.isExtern());
}
}
}
return false;
}
private FlowScope traverseName(Node n, FlowScope scope) {
String varName = n.getString();
Node value = n.getFirstChild();
JSType type = n.getJSType();
if (value != null) {
scope = traverse(value, scope);
updateScopeForTypeChange(scope, n, n.getJSType() /* could be null */,
getJSType(value));
return scope;
} else {
StaticSlot<JSType> var = scope.getSlot(varName);
if (var != null &&
!(var.isTypeInferred() && unflowableVarNames.contains(varName))) {
type = var.getType();
if (type == null) {
type = getNativeType(UNKNOWN_TYPE);
}
}
}
n.setJSType(type);
return scope;
}
/** Traverse each element of the array. */
private FlowScope traverseArrayLiteral(Node n, FlowScope scope) {
scope = traverseChildren(n, scope);
n.setJSType(getNativeType(ARRAY_TYPE));
return scope;
}
private FlowScope traverseObjectLiteral(Node n, FlowScope scope) {
if (n.getJSType() != null) {
// The node has already been traversed by the data-flow analysis
// framework. Don't re-generate the anonymous object as it might lead to
// pernicious bugs.
return scope;
}
ObjectType objectType = registry.createAnonymousObjectType();
for (Node name = n.getFirstChild(); name != null;
name = name.getNext().getNext()) {
Node value = name.getNext();
scope = traverse(name, scope);
scope = traverse(value, scope);
String memberName = NodeUtil.getStringValue(name);
if (memberName != null) {
// TODO(nicksantos): We need to fix the parser so that we can
// attach JSDoc to the
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS> individual elements of object literals.
// Right now, this is not possible.
objectType.defineInferredProperty(memberName, getJSType(value), false);
} else {
n.setJSType(getNativeType(UNKNOWN_TYPE));
return scope;
}
}
n.setJSType(objectType);
return scope;
}
private FlowScope traverseAdd(Node n, FlowScope scope) {
Node left = n.getFirstChild();
Node right = left.getNext();
scope = traverseChildren(n, scope);
JSType leftType = left.getJSType();
JSType rightType = right.getJSType();
JSType type = getNativeType(UNKNOWN_TYPE);
if (leftType != null && rightType != null) {
boolean leftIsUnknown = leftType.isUnknownType();
boolean rightIsUnknown = rightType.isUnknownType();
if (leftIsUnknown && rightIsUnknown) {
type = getNativeType(UNKNOWN_TYPE);
} else if ((!leftIsUnknown && leftType.isString()) ||
(!rightIsUnknown && rightType.isString())) {
type = getNativeType(STRING_TYPE);
} else if (leftIsUnknown || rightIsUnknown) {
type = getNativeType(UNKNOWN_TYPE);
} else if (isAddedAsNumber(leftType) && isAddedAsNumber(rightType)) {
type = getNativeType(NUMBER_TYPE);
} else {
type = registry.createUnionType(STRING_TYPE, NUMBER_TYPE);
}
}
n.setJSType(type);
if (n.getType() == Token.ASSIGN_ADD) {
updateScopeForTypeChange(scope, left, leftType, type);
}
return scope;
}
private boolean isAddedAsNumber(JSType type) {
return type.isSubtype(registry.createUnionType(VOID_TYPE, NULL_TYPE,
NUMBER_VALUE_OR_OBJECT_TYPE, BOOLEAN_TYPE, BOOLEAN_OBJECT_TYPE));
}
private FlowScope traverseHook(Node n, FlowScope scope) {
Node condition = n.getFirstChild();
Node trueNode = condition.getNext();
Node falseNode = n.getLastChild();
// verify the condition
scope = traverse(condition, scope);
// reverse abstract interpret
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>Parameter = true;
// Find the actual type of this argument.
if (j + 1 >= n.getChildCount()) {
// TypeCheck#visitParameterList will warn so we bail.
return;
}
Node jArgument = n.getChildAtIndex(j + 1);
JSType jArgumentType = getJSType(jArgument);
if (jArgument.getType() == Token.FUNCTION &&
jArgumentType instanceof FunctionType) {
// If it's an anonymous function, update the type of this
// using the actual type of T.
FunctionType jArgumentFnType =(FunctionType) jArgumentType;
if (jArgumentFnType.getTypeOfThis().isUnknownType()) {
// The new type will be picked up when we traverse the inner
// function.
jArgument.setJSType(
new FunctionType(
registry, jArgumentFnType.getReferenceName(),
jArgumentFnType.getSource(),
jArgumentFnType.getParametersNode(),
jArgumentFnType.getReturnType(),
(ObjectType) iArgumentType));
}
}
// TODO(user): Add code to TypeCheck to check that the
// types of the arguments match.
}
}
j++;
}
if (!foundTemplateTypeOfThisParameter) {
Node source = fnType.getSource();
compiler.report(JSError.make(NodeUtil.getSourceName(source), source,
TEMPLATE_TYPE_OF_THIS_EXPECTED));
return;
}
}
}
i++;
}
}
private FlowScope traverseNew(Node n, FlowScope scope) {
Node constructor = n.getFirstChild();
scope = traverse(constructor, scope);
JSType constructorType = constructor.getJSType();
JSType type = null;
if (constructorType != null) {
constructorType = constructorType.restrictByNotNullOrUndefined();
if (constructorType.isUnknownType()) {
type = getNativeType(UNKNOWN_TYPE);
} else if (constructorType instanceof FunctionType) {
FunctionType ct = (FunctionType) constructorType;
if (ct.isConstructor()) {
type = ct.getInstanceType();
}
}
}
n.setJSType(type);
for (Node arg = constructor.getNext(); arg != null; arg = arg.getNext()) {
scope = traverse(arg,
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>Type.equals(getNativeType(UNKNOWN_TYPE)) &&
var != syntacticScope.getSlot(qualifiedName)) {
// If the type of this qualified name has been checked in this scope,
// then use CHECKED_UNKNOWN_TYPE instead to indicate that.
return getNativeType(CHECKED_UNKNOWN_TYPE);
} else {
return varType;
}
}
}
JSType propertyType = null;
if (objType != null) {
propertyType = objType.findPropertyType(propName);
}
if ((propertyType == null || propertyType.isUnknownType()) &&
qualifiedName != null) {
// If we find this node in the registry, then we can infer its type.
ObjectType regType = ObjectType.cast(registry.getType(qualifiedName));
if (regType != null) {
propertyType = regType.getConstructor();
}
}
return propertyType;
}
private BooleanOutcomePair traverseOr(Node n, FlowScope scope) {
return traverseShortCircuitingBinOp(n, scope, false);
}
private BooleanOutcomePair traverseShortCircuitingBinOp(
Node n, FlowScope scope, boolean condition) {
Node left = n.getFirstChild();
Node right = n.getLastChild();
// type the left node
BooleanOutcomePair leftLiterals =
traverseWithinShortCircuitingBinOp(left,
scope.createChildFlowScope());
JSType leftType = left.getJSType();
// reverse abstract interpret the left node to produce the correct
// scope in which to verify the right node
FlowScope rightScope = reverseInterpreter.
getPreciserScopeKnowingConditionOutcome(
left, leftLiterals.getOutcomeFlowScope(left.getType(), condition),
condition);
// type the right node
BooleanOutcomePair rightLiterals =
traverseWithinShortCircuitingBinOp(
right, rightScope.createChildFlowScope());
JSType rightType = right.getJSType();
JSType type;
BooleanOutcomePair literals;
if (leftType != null && rightType != null) {
leftType = leftType.getRestrictedTypeGivenToBooleanOutcome(!condition);
if (leftLiterals.toBooleanOutcomes ==
BooleanLiteralSet.get(!condition)) {
// Use the restricted left type, since the right
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS> the entire
* expression.
*/
FlowScope getOutcomeFlowScope(int nodeType, boolean outcome) {
if (nodeType == Token.AND && outcome ||
nodeType == Token.OR && !outcome) {
// We know that the whole expression must have executed.
return rightScope;
} else {
return getJoinedFlowScope();
}
}
}
private BooleanOutcomePair newBooleanOutcomePair(
JSType jsType, FlowScope flowScope) {
if (jsType == null) {
return new BooleanOutcomePair(
BooleanLiteralSet.BOTH, BooleanLiteralSet.BOTH, flowScope, flowScope);
}
return new BooleanOutcomePair(jsType.getPossibleToBooleanOutcomes(),
registry.getNativeType(BOOLEAN_TYPE).isSubtype(jsType) ?
BooleanLiteralSet.BOTH : BooleanLiteralSet.EMPTY,
flowScope, flowScope);
}
private void redeclare(FlowScope scope, String varName, JSType varType) {
if (varType == null) {
varType = getNativeType(JSTypeNative.UNKNOWN_TYPE);
}
if (unflowableVarNames.contains(varName)) {
return;
}
scope.inferSlotType(varName, varType);
}
/**
* This method gets the JSType from the Node argument and verifies that it is
* present.
*/
private JSType getJSType(Node n) {
JSType jsType = n.getJSType();
if (jsType == null) {
// TODO(nicksantos): This branch indicates a compiler bug, not worthy of
// halting the compilation but we should log this and analyze to track
// down why it happens. This is not critical and will be resolved over
// time as the type checker is extended.
return getNativeType(UNKNOWN_TYPE);
} else {
return jsType;
}
}
private JSType getNativeType(JSTypeNative typeId) {
return registry.getNativeType(typeId);
}
}
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>/*
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1997-1999
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Bob Jervis
* Google Inc.
*
* Alternatively, the contents of this file may be used under the terms of
* the GNU General Public License Version 2 or later (the "GPL"), in which
* case the provisions of the GPL are applicable instead of those above. If
* you wish to allow use of your version of this file only under the terms of
* the GPL and not to allow others to use your version of this file under the
* MPL, indicate your decision by deleting the provisions above and replacing
* them with the notice and other provisions required by the GPL. If you do
* not delete the provisions above, a recipient may use your version of this
* file under either the MPL or the GPL.
*
* ***** END LICENSE BLOCK ***** */
package com.google.javascript.rhino.jstype;
import static com.google.javascript.rhino.jstype.TernaryValue.FALSE;
import static com.google.javascript.rhino.jstype.TernaryValue.UNKNOWN;
/**
* String type.
*
*/
public final class StringType extends ValueType {
private static final long serialVersionUID = 1L;
StringType(JSTypeRegistry registry) {
super(registry);
}
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>
*/
public final class JSTypeExpression implements Serializable {
private static final long serialVersionUID = 1L;
/** The root of the AST. */
private final Node root;
/** The source name where the type expression appears. */
private final String sourceName;
/** The type registry to use for resolution. */
private final JSTypeRegistry registry;
public JSTypeExpression(Node root, String sourceName,
JSTypeRegistry registry) {
this.root = root;
this.sourceName = sourceName;
this.registry = registry;
}
/**
* Make the given type expression into an optional type expression,
* if possible.
*/
public static JSTypeExpression makeOptionalArg(JSTypeExpression expr) {
if (expr.isOptionalArg() || expr.isVarArgs()) {
return expr;
} else {
return new JSTypeExpression(
new Node(Token.EQUALS, expr.root), expr.sourceName, expr.registry);
}
}
/**
* @return Whether this expression denotes an optional {@code @param}.
*/
public boolean isOptionalArg() {
return root.getType() == Token.EQUALS;
}
/**
* @return Whether this expression denotes a rest args {@code @param}.
*/
public boolean isVarArgs() {
return root.getType() == Token.ELLIPSIS;
}
/**
* Evaluates the type expression into a {@code JSType} object.
*/
public JSType evaluate(StaticScope<JSType> scope) {
JSType type = registry.createFromTypeNodes(root, sourceName, scope);
if (root.getBooleanProp(Node.BRACELESS_TYPE)) {
type.forgiveUnknownNames();
}
return type;
}
@Override
public boolean equals(Object other) {
return other instanceof JSTypeExpression &&
((JSTypeExpression) other).root.checkTreeEqualsSilent(root);
}
@Override
public int hashCode() {
return root.toStringTree().hashCode();
}
}
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>/*
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1997-1999
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Bob Jervis
* Google Inc.
*
* Alternatively, the contents of this file may be used under the terms of
* the GNU General Public License Version 2 or later (the "GPL"), in which
* case the provisions of the GPL are applicable instead of those above. If
* you wish to allow use of your version of this file only under the terms of
* the GPL and not to allow others to use your version of this file under the
* MPL, indicate your decision by deleting the provisions above and replacing
* them with the notice and other provisions required by the GPL. If you do
* not delete the provisions above, a recipient may use your version of this
* file under either the MPL or the GPL.
*
* ***** END LICENSE BLOCK ***** */
package com.google.javascript.rhino.jstype;
/**
* An object type with a declared default index type.
*
* For example, <code>Object.<number, string></code> can take only numbers as
* keys.
*
*
*/
final class IndexedType extends ProxyObjectType {
private static final long serialVersionUID = 1L;
final JSType indexType;
IndexedType(
JSTypeRegistry registry, ObjectType objectType, JSType index
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>Type) {
super(registry, objectType);
this.indexType = indexType;
}
@Override
public JSType getIndexType() {
return indexType;
}
}
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>Native.
private final boolean isChecked;
UnknownType(JSTypeRegistry registry, boolean isChecked) {
super(registry);
this.isChecked = isChecked;
}
@Override
public boolean isUnknownType() {
return true;
}
@Override
public boolean isCheckedUnknownType() {
return isChecked;
}
@Override
public boolean canAssignTo(JSType that) {
return true;
}
@Override
public boolean canBeCalled() {
return true;
}
@Override
public boolean matchesNumberContext() {
return true;
}
@Override
public boolean matchesObjectContext() {
return true;
}
@Override
public boolean matchesStringContext() {
return true;
}
@Override
public TernaryValue testForEquality(JSType that) {
return UNKNOWN;
}
@Override
public boolean isNullable() {
return true;
}
@Override
public boolean isSubtype(JSType that) {
return true;
}
@Override
public JSType getLeastSupertype(JSType that) {
return this;
}
@Override
public JSType getGreatestSubtype(JSType that) {
return this;
}
@Override
public <T> T visit(Visitor<T> visitor) {
return visitor.caseUnknownType();
}
@Override
public String toString() {
return getReferenceName();
}
@Override
boolean defineProperty(String propertyName, JSType type,
boolean inferred, boolean inExterns) {
// nothing to define
return true;
}
@Override
public ObjectType getImplicitPrototype() {
return null;
}
@Override
public int getPropertiesCount() {
return Integer.MAX_VALUE;
}
@Override
protected void collectPropertyNames(Set<String> props) {
}
@Override
public JSType getPropertyType(String propertyName) {
return this;
}
@Override
public boolean hasProperty(String propertyName) {
return true;
}
@Override
public FunctionType getConstructor() {
return null;
}
@Override
public String getReferenceName() {
return isChecked ? "??" : "?";
}
@Override
public boolean isPropertyTypeDeclared(String propertyName) {
return false;
}
@
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS> {
private static final long serialVersionUID = 1L;
VoidType(JSTypeRegistry registry) {
super(registry);
}
@Override
public JSType restrictByNotNullOrUndefined() {
return registry.getNativeType(JSTypeNative.NO_TYPE);
}
@Override
public TernaryValue testForEquality(JSType that) {
if (UNKNOWN.equals(super.testForEquality(that))) {
return UNKNOWN;
}
if (that.isSubtype(this) ||
that.isSubtype(getNativeType(JSTypeNative.NULL_TYPE))) {
return TRUE;
}
return FALSE;
}
@Override
public boolean matchesNumberContext() {
return false;
}
@Override
public boolean matchesObjectContext() {
return false;
}
@Override
public boolean matchesStringContext() {
return true;
}
@Override
public boolean isVoidType() {
return true;
}
@Override
public String toString() {
return "undefined";
}
@Override
public BooleanLiteralSet getPossibleToBooleanOutcomes() {
return BooleanLiteralSet.FALSE;
}
@Override
public <T> T visit(Visitor<T> visitor) {
return visitor.caseVoidType();
}
}
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS> getJSType(n.getLastChild());
if (rightType.isNumber()) {
validator.expectNumber(
t, n, leftType, "left side of numeric comparison");
} else if (leftType.isNumber()) {
validator.expectNumber(
t, n, rightType, "right side of numeric comparison");
} else if (leftType.matchesNumberContext() &&
rightType.matchesNumberContext()) {
// OK.
} else {
// Whether the comparison is numeric will be determined at runtime
// each time the expression is evaluated. Regardless, both operands
// should match a string context.
String message = "left side of comparison";
validator.expectString(t, n, leftType, message);
validator.expectNotVoid(
t, n, leftType, message, getNativeType(STRING_TYPE));
message = "right side of comparison";
validator.expectString(t, n, rightType, message);
validator.expectNotVoid(
t, n, rightType, message, getNativeType(STRING_TYPE));
}
ensureTyped(t, n, BOOLEAN_TYPE);
break;
case Token.IN:
left = n.getFirstChild();
right = n.getLastChild();
leftType = getJSType(left);
rightType = getJSType(right);
validator.expectObject(t, n, rightType, "'in' requires an object");
validator.expectString(t, left, leftType, "left side of 'in'");
ensureTyped(t, n, BOOLEAN_TYPE);
break;
case Token.INSTANCEOF:
left = n.getFirstChild();
right = n.getLastChild();
leftType = getJSType(left);
rightType = getJSType(right).restrictByNotNullOrUndefined();
validator.expectAnyObject(
t, left, leftType, "deterministic instanceof yields false");
validator.expectActualObject(
t, right, rightType, "instanceof requires an object");
ensureTyped(t, n, BOOLEAN_TYPE);
break;
case Token.ASSIGN:
visitAssign(t, n);
typeable = false;
break;
case Token.ASSIGN_LSH:
case Token.ASSIGN_RSH:
case Token.ASSIGN_URSH:
case
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>getString(), t, n);
ensureTyped(t, n);
}
/**
* Make sure that the access of this property is ok.
*/
private void checkPropertyAccess(JSType childType, String propName,
NodeTraversal t, Node n) {
ObjectType objectType = childType.dereference();
if (objectType != null) {
JSType propType = getJSType(n);
if ((!objectType.hasProperty(propName) ||
objectType.equals(typeRegistry.getNativeType(UNKNOWN_TYPE))) &&
propType.equals(typeRegistry.getNativeType(UNKNOWN_TYPE))) {
if (objectType instanceof EnumType) {
t.report(n, INEXISTENT_ENUM_ELEMENT, propName);
} else if (!objectType.isEmptyType() &&
reportMissingProperties && !isPropertyTest(n)) {
if (!typeRegistry.canPropertyBeDefined(objectType, propName)) {
t.report(n, INEXISTENT_PROPERTY, propName,
validator.getReadableJSTypeName(n.getFirstChild(), true));
}
}
}
} else {
// TODO(nicksantos): might want to flag the access on a non object when
// it's impossible to get a property from this type.
}
}
/**
* Determines whether this node is testing for the existence of a property.
* If true, we will not emit warnings about a missing property.
*
* @param getProp The GETPROP being tested.
*/
private boolean isPropertyTest(Node getProp) {
Node parent = getProp.getParent();
switch (parent.getType()) {
case Token.CALL:
return parent.getFirstChild() != getProp &&
compiler.getCodingConvention().isPropertyTestFunction(parent);
case Token.IF:
case Token.WHILE:
case Token.DO:
case Token.FOR:
return NodeUtil.getConditionExpression(parent) == getProp;
case Token.INSTANCEOF:
case Token.TYPEOF:
return true;
case Token.AND:
case Token.HOOK:
return parent.getFirstChild() == getProp;
}
return false;
}
/**
* Visits a GETELEM node.
*
* @param t The node traversal object that
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>.mozilla.rhino.ast.SwitchStatement;
import com.google.javascript.jscomp.mozilla.rhino.ast.ThrowStatement;
import com.google.javascript.jscomp.mozilla.rhino.ast.TryStatement;
import com.google.javascript.jscomp.mozilla.rhino.ast.UnaryExpression;
import com.google.javascript.jscomp.mozilla.rhino.ast.VariableDeclaration;
import com.google.javascript.jscomp.mozilla.rhino.ast.VariableInitializer;
import com.google.javascript.jscomp.mozilla.rhino.ast.WhileLoop;
import com.google.javascript.jscomp.mozilla.rhino.ast.WithStatement;
import com.google.javascript.rhino.JSDocInfo;
import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.ScriptOrFnNode;
import com.google.javascript.rhino.Token;
import com.google.javascript.rhino.jstype.JSTypeRegistry;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
/**
* IRFactory transforms the new AST to the old AST.
*
*
*/
public class IRFactory {
private final String sourceString;
private final String sourceName;
private final Config config;
private final JSTypeRegistry registry;
private final ErrorReporter errorReporter;
private final TransformDispatcher transformDispatcher;
// non-static for thread safety
private final Set<String> ALLOWED_DIRECTIVES = Sets.newHashSet("use strict");
// Nodes with JSDoc comments, indexed by the text of the JSDoc comment.
//
// It's likely that two or more nodes in the same file may have the same
// jsdoc comment. In general, that's ok.
//
// There's one edge case where this might cause problems. If two JSDoc
// comments have the same text, and the first JSDoc comment is not attached
// to a node, then the second node will get the first JSDoc comment
// instead of the second. When this happens, it probably won't cause any
// problems. The two JSDoc comments will be exactly the same,
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS> except for
// their line numbers. Their line numbers will only be exposed for
// type name resolution warnings.
//
// TODO(nicksantos): Change rhino to put the whole Comment object
// on the Node.
private final Multimap<String, NodeWithJsDoc> nodesWithJsDoc =
LinkedHashMultimap.create();
private IRFactory(String sourceString,
String sourceName,
Config config,
ErrorReporter errorReporter) {
this.sourceString = sourceString;
this.sourceName = sourceName;
this.registry = config.registry;
this.config = config;
this.errorReporter = errorReporter;
this.transformDispatcher = new TransformDispatcher();
}
public static Node transformTree(AstRoot node,
String sourceString,
Config config,
ErrorReporter errorReporter) {
IRFactory irFactory = new IRFactory(sourceString, node.getSourceName(),
config, errorReporter);
Node irNode = irFactory.transform(node);
// @license text gets appended onto the fileLevelJsDocBuilder as found,
// and stored straight into the JSDocInfo for the root node.
Node.FileLevelJsDocBuilder fileLevelJsDocBuilder =
irNode.getJsDocBuilderForNode();
// fileOverviewInfo stores the last bit of fileoverview data we saw.
// We only permit one, so throwing away extras is fair.
// The fileOverviewInfo gets passed into parseJSDocInfo so that
// it can detect when multiple @fileoverviews exist in the same file.
JSDocInfo fileOverviewInfo = null;
if (node.getComments() != null) {
for (Comment comment : node.getComments()) {
if (comment.getCommentType() == JSDOC) {
JsDocInfoParser jsDocParser =
irFactory.createJsDocInfoParser(comment.getValue(),
comment.getLineno(), comment.getAbsolutePosition(),
fileLevelJsDocBuilder, fileOverviewInfo);
if (jsDocParser.getFileOverviewJSDocInfo() != fileOverviewInfo) {
fileOverviewInfo = jsDocParser.getFileOverviewJSDocInfo();
} else {
JSDocInfo info = jsDocParser.retrieveAndResetParsedJSDocInfo();
if (info != null) {
irFactory.attachJs
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>
* @param comment The JsDoc comment to parse.
* @param lineno The line number of the node this comment is attached to.
* @param fileLevelJsDocBuilder The builder for file-level JSDocInfo.
* @param fileOverviewInfo The current @fileoverview JSDocInfo, so that the
* parser may warn if another @fileoverview is found. May be null.
* @return A JSDocInfoParser. Will contain either fileoverview jsdoc, or
* normal jsdoc, or no jsdoc (if the method parses to the wrong level).
*/
private JsDocInfoParser createJsDocInfoParser(
String comment, int lineno, int position,
Node.FileLevelJsDocBuilder fileLevelJsDocBuilder,
JSDocInfo fileOverviewInfo) {
// The JsDocInfoParser expects the comment without the initial '/**'.
int numOpeningChars = 3;
JsDocInfoParser jsdocParser =
new JsDocInfoParser(
new JsDocTokenStream(comment.substring(numOpeningChars),
lineno,
position2charno(position) + numOpeningChars),
sourceName,
config,
errorReporter);
jsdocParser.setFileLevelJsDocBuilder(fileLevelJsDocBuilder);
jsdocParser.setFileOverviewJSDocInfo(fileOverviewInfo);
jsdocParser.parse();
return jsdocParser;
}
/** Attach JSDocInfo to a node, if we can find one. */
private void attachJsDoc(Comment comment, JSDocInfo info) {
Collection<NodeWithJsDoc> candidates =
nodesWithJsDoc.get(comment.getValue());
if (candidates.isEmpty()) {
return;
}
Iterator<NodeWithJsDoc> candidateIter = candidates.iterator();
Node node = candidateIter.next().node;
candidateIter.remove();
node.setJSDocInfo(info);
if (info.hasEnumParameterType()) {
if (node.getType() == Token.NAME) {
registry.identifyEnumName(node.getString());
} else if (node.getType() == Token.VAR &&
node.getChildCount() == 1) {
registry.identifyEnumName(
node.getFirstChild().getString());
} else if (node.getType() == Token.ASSIGN
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>) {
registry.identifyEnumName(
node.getFirstChild().getQualifiedName());
}
}
}
private int position2charno(int position) {
int lineIndex = sourceString.lastIndexOf('\n', position);
if (lineIndex == -1) {
return position;
} else {
// Subtract one for initial position being 0.
return position - lineIndex - 1;
}
}
private Node justTransform(AstNode node) {
return transformDispatcher.process(node);
}
private class TransformDispatcher extends TypeSafeDispatcher<Node> {
private Node processGeneric(
com.google.javascript.jscomp.mozilla.rhino.Node n) {
Node node = new Node(transformTokenType(n.getType()));
for (com.google.javascript.jscomp.mozilla.rhino.Node child : n) {
node.addChildToBack(transform((AstNode)child));
}
return node;
}
/**
* Transforms the given node and then sets its type to Token.STRING if it
* was Token.NAME. If its type was already Token.STRING, then quotes it.
* Used for properties, as the old AST uses String tokens, while the new one
* uses Name tokens for unquoted strings. For example, in
* var o = {'a' : 1, b: 2};
* the string 'a' is quoted, while the name b is turned into a string, but
* unquoted.
*/
private Node transformAsString(AstNode n) {
Node ret = transform(n);
if (ret.getType() == Token.STRING) {
ret.putBooleanProp(Node.QUOTED_PROP, true);
} else if (ret.getType() == Token.NAME) {
ret.setType(Token.STRING);
}
return ret;
}
@Override
Node processArrayLiteral(ArrayLiteral literalNode) {
if (literalNode.isDestructuring()) {
reportDestructuringAssign(literalNode);
}
Node node = new Node(Token.ARRAYLIT);
int skipCount = 0;
for (AstNode child : literalNode.getElements()) {
Node c = transform(child);
if (c.getType() == Token.EMPTY) {
skipCount++;
}
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS> case com.google.javascript.jscomp.mozilla.rhino.Token.TRUE:
return Token.TRUE;
case com.google.javascript.jscomp.mozilla.rhino.Token.SHEQ:
return Token.SHEQ;
case com.google.javascript.jscomp.mozilla.rhino.Token.SHNE:
return Token.SHNE;
case com.google.javascript.jscomp.mozilla.rhino.Token.REGEXP:
return Token.REGEXP;
case com.google.javascript.jscomp.mozilla.rhino.Token.BINDNAME:
return Token.BINDNAME;
case com.google.javascript.jscomp.mozilla.rhino.Token.THROW:
return Token.THROW;
case com.google.javascript.jscomp.mozilla.rhino.Token.RETHROW:
return Token.RETHROW;
case com.google.javascript.jscomp.mozilla.rhino.Token.IN:
return Token.IN;
case com.google.javascript.jscomp.mozilla.rhino.Token.INSTANCEOF:
return Token.INSTANCEOF;
case com.google.javascript.jscomp.mozilla.rhino.Token.LOCAL_LOAD:
return Token.LOCAL_LOAD;
case com.google.javascript.jscomp.mozilla.rhino.Token.GETVAR:
return Token.GETVAR;
case com.google.javascript.jscomp.mozilla.rhino.Token.SETVAR:
return Token.SETVAR;
case com.google.javascript.jscomp.mozilla.rhino.Token.CATCH_SCOPE:
return Token.CATCH_SCOPE;
case com.google.javascript.jscomp.mozilla.rhino.Token.ENUM_INIT_KEYS:
return Token.ENUM_INIT_KEYS;
case com.google.javascript.jscomp.mozilla.rhino.Token.ENUM_INIT_VALUES:
return Token.ENUM_INIT_VALUES;
case com.google.javascript.jscomp.mozilla.rhino.Token.ENUM_NEXT:
return Token.ENUM_NEXT;
case com.google.javascript.jscomp.mozilla.rhino.Token.ENUM_ID:
return Token.ENUM_ID;
case com.google.javascript.jscomp.mozilla.rhino.Token.THISFN
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>/*
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1997-1999
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Bob Jervis
* Google Inc.
*
* Alternatively, the contents of this file may be used under the terms of
* the GNU General Public License Version 2 or later (the "GPL"), in which
* case the provisions of the GPL are applicable instead of those above. If
* you wish to allow use of your version of this file only under the terms of
* the GPL and not to allow others to use your version of this file under the
* MPL, indicate your decision by deleting the provisions above and replacing
* them with the notice and other provisions required by the GPL. If you do
* not delete the provisions above, a recipient may use your version of this
* file under either the MPL or the GPL.
*
* ***** END LICENSE BLOCK ***** */
package com.google.javascript.rhino.jstype;
import com.google.javascript.rhino.ErrorReporter;
/**
* Value types (null, void, number, boolean, string).
*/
abstract class ValueType extends JSType {
ValueType(JSTypeRegistry registry) {
super(registry);
}
@Override
public boolean isSubtype(JSType that) {
return JSType.isSubtype(this, that);
}
@Override
final JS
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>/**
* The object type represents instances of JavaScript objects such as
* {@code Object}, {@code Date}, {@code Function}.<p>
*
* Objects in JavaScript are unordered collections of properties.
* Each property consists of a name, a value and a set of attributes.<p>
*
* Each instance has an implicit prototype property ({@code [[Prototype]]})
* pointing to an object instance, which itself has an implicit property, thus
* forming a chain.<p>
*
* A class begins life with no name. Later, a name may be provided once it
* can be inferred. Note that the name in this case is strictly for
* debugging purposes. Looking up type name references goes through the
* {@link JSTypeRegistry}.<p>
*/
class PrototypeObjectType extends ObjectType {
private static final long serialVersionUID = 1L;
private final String className;
private final Map<String, Property> properties;
private ObjectType implicitPrototype;
private final boolean nativeType;
/**
* Creates an object type.
*
* @param className the name of the class. May be {@code null} to
* denote an anonymous class.
*
* @param implicitPrototype the implicit prototype
* (a.k.a. {@code [[Prototype]]}) as defined by ECMA-262. If the
* implicit prototype is {@code null} the implicit prototype will be
* set to the {@link JSTypeNative#OBJECT_TYPE}.
*/
PrototypeObjectType(JSTypeRegistry registry, String className,
ObjectType implicitPrototype) {
this(registry, className, implicitPrototype, false);
}
/**
* Creates an object type, allowing specification of the implicit prototype
* when creating native objects.
*/
PrototypeObjectType(JSTypeRegistry registry, String className,
ObjectType implicitPrototype, boolean nativeType) {
super(registry);
this.properties = Maps.newHashMap();
this.className = className;
this.nativeType = nativeType;
if (nativeType) {
this.implicitPrototype = implicitPrototype;
} else if (implicitPrototype == null) {
this.implicitPrototype =
registry.getNativeObjectType(JSTypeNative.OBJECT_TYPE);
} else {
this.implicitPrototype = implicitPrototype;
}
}
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>NativeProperty("toString");
}
/**
* Given the name of a native object property, checks whether the property is
* present on the object and different from the native one.
*/
private boolean hasOverridenNativeProperty(String propertyName) {
if (isNative()) {
return false;
}
JSType propertyType = getPropertyType(propertyName);
ObjectType nativeType =
this.isFunctionType() ?
registry.getNativeObjectType(JSTypeNative.FUNCTION_PROTOTYPE) :
registry.getNativeObjectType(JSTypeNative.OBJECT_PROTOTYPE);
JSType nativePropertyType = nativeType.getPropertyType(propertyName);
return propertyType != nativePropertyType;
}
@Override
public JSType unboxesTo() {
if (isStringObjectType()) {
return getNativeType(JSTypeNative.STRING_TYPE);
} else if (isBooleanObjectType()) {
return getNativeType(JSTypeNative.BOOLEAN_TYPE);
} else if (isNumberObjectType()) {
return getNativeType(JSTypeNative.NUMBER_TYPE);
} else {
return super.unboxesTo();
}
}
@Override
public boolean matchesObjectContext() {
return true;
}
@Override
public boolean canBeCalled() {
return isRegexpType();
}
/**
* Whether this represents a native type (such as Object, Date,
* RegExp, etc.).
*/
boolean isNative() {
return nativeType;
}
@Override
public String toString() {
return getReferenceName();
}
@Override
public FunctionType getConstructor() {
return null;
}
@Override
public ObjectType getImplicitPrototype() {
return implicitPrototype;
}
/**
* This should only be reset on the FunctionPrototypeType, only to fix an
* incorrectly established prototype chain due to the user having a mismatch
* in super class declaration, and only before properties on that type are
* processed.
*/
void setImplicitPrototype(ObjectType implicitPrototype) {
checkState(!hasCachedValues());
this.implicitPrototype = implicitPrototype;
}
@Override
public String getReferenceName() {
if (className != null) {
return className;
} else {
return "{...}";
}
}
@Override
public boolean hasReferenceName() {
return className != null;
}
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>SDocInfo;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Object type.
*
* In JavaScript, all object types have properties, and each of those
* properties has a type. Property types may be DECLARED, INFERRED, or
* UNKNOWN.
*
* DECLARED properties have an explicit type annotation, as in:
* <code>
* /xx @type {number} x/
* Foo.prototype.bar = 1;
* </code>
* This property may only hold number values, and an assignment to any
* other type of value is an error.
*
* INFERRED properties do not have an explicit type annotation. Rather,
* we try to find all the possible types that this property can hold.
* <code>
* Foo.prototype.bar = 1;
* </code>
* If the programmer assigns other types of values to this property,
* the property will take on the union of all these types.
*
* UNKNOWN properties are properties on the UNKNOWN type. The UNKNOWN
* type has all properties, but we do not know whether they are
* declared or inferred.
*
*
*/
public abstract class ObjectType extends JSType {
private boolean visited;
private JSDocInfo docInfo = null;
private boolean unknown = true;
ObjectType(JSTypeRegistry registry) {
super(registry);
}
/**
* Gets the declared default element type.
* @see ParameterizedType
*/
public JSType getParameterType() {
return null;
}
/**
* Gets the declared default index type.
* @see IndexedType
*/
public JSType getIndexType() {
return null;
}
/**
* Gets the docInfo for this type.
*/
@Override public JSDocInfo getJSDocInfo() {
if (docInfo != null) {
return docInfo;
} else if (getImplicitPrototype() != null) {
return getImplicitPrototype().getJSDocInfo();
} else {
return super.getJSDocInfo();
}
}
/**
* Sets the docInfo for this type from the given
* {@link JSDocInfo}. The {@code JSDocInfo} may be
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>();
/**
* Gets the implicit prototype (a.k.a. the {@code [[Prototype]]} property).
*/
public abstract ObjectType getImplicitPrototype();
/**
* Defines a property whose type is synthesized (i.e. not inferred).
* @param propertyName the property's name
* @param type the type
* @param inExterns {@code true} if this property was defined in an externs
* file. TightenTypes assumes that any function passed to an externs
* property could be called, so setting this incorrectly could result
* in live code being removed.
*/
public final boolean defineDeclaredProperty(String propertyName,
JSType type, boolean inExterns) {
// All property definitions go through this method
// or defineInferredProperty.
registry.registerPropertyOnType(propertyName, this);
return defineProperty(propertyName, type, false, inExterns);
}
/**
* Defines a property whose type is inferred.
* @param propertyName the property's name
* @param type the type
* @param inExterns {@code true} if this property was defined in an externs
* file. TightenTypes assumes that any function passed to an externs
* property could be called, so setting this incorrectly could result
* in live code being removed.
*/
public final boolean defineInferredProperty(String propertyName,
JSType type, boolean inExterns) {
// All property definitions go through this method
// or defineDeclaredProperty.
registry.registerPropertyOnType(propertyName, this);
if (hasProperty(propertyName)) {
JSType originalType = getPropertyType(propertyName);
type = originalType == null ? type :
originalType.getLeastSupertype(type);
}
return defineProperty(propertyName, type, true, inExterns);
}
/**
* Defines a property.<p>
*
* For clarity, callers should prefer {@link #defineDeclaredProperty} and
* {@link #defineInferredProperty}.
*
* @param propertyName the property's name
* @param type the type
* @param inferred {@code true} if this property's type is inferred
* @param inExterns {@code true} if this property was defined in an externs
* file
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>
/**
* Create a named type based on the reference.
*/
public NamedType(JSTypeRegistry registry, String reference,
String sourceName, int lineno, int charno) {
super(registry, registry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE));
Preconditions.checkNotNull(reference);
this.reference = reference;
this.sourceName = sourceName;
this.lineno = lineno;
this.charno = charno;
}
@Override
public void forgiveUnknownNames() {
forgiving = true;
}
/** Returns the type to which this refers (which is unknown if unresolved). */
public JSType getReferencedType() {
return referencedType;
}
@Override
public String getReferenceName() {
return reference;
}
@Override
public String toString() {
return reference;
}
@Override
public boolean hasReferenceName() {
return true;
}
@Override
public boolean isNamedType() {
return true;
}
@Override
public boolean isNominalType() {
return true;
}
/**
* Two named types are equal if they are the same {@code ObjectType} object.
* This is complicated by the fact that equals is sometimes called before we
* have a chance to resolve the type names.
*
* @return {@code true} iff {@code that} == {@code this} or {@code that}
* is a {@link NamedType} whose reference is the same as ours,
* or {@code that} is the type we reference.
*/
@Override
public boolean equals(Object that) {
if (this == that) {
return true;
} else if (that instanceof JSType) {
ObjectType objType = ObjectType.cast((JSType) that);
if (objType != null) {
return objType.isNominalType() &&
reference.equals(objType.getReferenceName());
}
}
return false;
}
@Override
public int hashCode() {
return reference.hashCode();
}
/**
* Resolve the referenced type within the enclosing scope.
*/
@Override
JSType resolveInternal(ErrorReporter t, StaticScope<JSType> enclosing) {
// TODO(user): Investigate whether it is really necessary to keep two
// different
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS> mechanisms for resolving named types, and if so, which order
// makes more sense. Now, resolution via registry is first in order to
// avoid triggering the warnings built into the resolution via properties.
boolean resolved = resolveViaRegistry(t, enclosing);
if (detectImplicitPrototypeCycle()) {
handleTypeCycle(t);
}
if (resolved) {
super.resolveInternal(t, enclosing);
return referencedType;
}
resolveViaProperties(t, enclosing);
if (detectImplicitPrototypeCycle()) {
handleTypeCycle(t);
}
super.resolveInternal(t, enclosing);
return referencedType;
}
/**
* Resolves a named type by looking it up in the registry.
* @return True if we resolved successfully.
*/
private boolean resolveViaRegistry(
ErrorReporter t, StaticScope<JSType> enclosing) {
ObjectType type = ObjectType.cast(registry.getType(reference));
if (type != null) {
setReferencedType(type, t, enclosing);
return true;
}
return false;
}
/**
* Resolves a named type by looking up its first component in the scope, and
* subsequent components as properties. The scope must have been fully
* parsed and a symbol table constructed.
*/
private void resolveViaProperties(ErrorReporter t,
StaticScope<JSType> enclosing) {
String[] componentNames = reference.split("\\.", -1);
if (componentNames[0].length() == 0) {
handleUnresolvedType(t);
return;
}
StaticSlot<JSType> slot = enclosing.getSlot(componentNames[0]);
if (slot == null) {
handleUnresolvedType(t);
return;
}
// If the first component has a type of 'Unknown', then any type
// names using it should be regarded as silently 'Unknown' rather than be
// noisy about it.
JSType slotType = slot.getType();
if (slotType == null || slotType.isAllType() || slotType.isNoType()) {
handleUnresolvedType(t);
return;
}
JSType value = getTypedefType(t, slot, componentNames[0]);
if (value == null) {
handleUnresolvedType(t);
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>
return;
}
// resolving component by component
for (int i = 1; i < componentNames.length; i++) {
ObjectType parentClass = ObjectType.cast(value);
if (parentClass == null) {
handleUnresolvedType(t);
return;
}
if (componentNames[i].length() == 0) {
handleUnresolvedType(t);
return;
}
value = parentClass.getPropertyType(componentNames[i]);
}
// last component of the chain
if (value instanceof FunctionType) {
FunctionType functionType = (FunctionType)value;
if (functionType.isConstructor() || functionType.isInterface()) {
setReferencedType(functionType.getInstanceType(), t, enclosing);
} else {
handleUnresolvedType(t);
}
} else if (value instanceof EnumType) {
setReferencedType(((EnumType) value).getElementsType(), t, enclosing);
} else {
handleUnresolvedType(t);
}
}
private void setReferencedType(ObjectType type, ErrorReporter t,
StaticScope<JSType> enclosing) {
referencedType = type;
checkEnumElementCycle(t);
setResolvedTypeInternal(referencedType);
}
private void handleTypeCycle(ErrorReporter t) {
referencedType = registry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE);
t.warning("Cycle detected in inheritance chain of type " + reference,
sourceName, lineno, null, charno);
setResolvedTypeInternal(referencedType);
}
private void checkEnumElementCycle(ErrorReporter t) {
if (referencedType instanceof EnumElementType &&
((EnumElementType) referencedType).getPrimitiveType() == this) {
handleTypeCycle(t);
}
}
// Warns about this type being unresolved iff it's not a forward-declared
// type name.
private void handleUnresolvedType(ErrorReporter t) {
if (!registry.isForwardDeclaredType(reference) && !forgiving &&
registry.isLastGeneration()) {
t.warning("Unknown type " + reference, sourceName, lineno, null,
charno);
} else {
referencedType = registry.getNativeObjectType(
JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
setResolvedType
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS> assign {@code x} a type within the {@code f(x)}
* call. Since it has no possible type, we assign {@code x} the NoType,
* so that {@code f(x)} is legal no matter what the type of {@code f}'s
* first argument is.
*
*
* @see <a href="http://en.wikipedia.org/wiki/Bottom_type">Bottom types</a>
*/
public final class NoType extends NoObjectType {
private static final long serialVersionUID = 1L;
NoType(JSTypeRegistry registry) {
super(registry);
}
@Override
public boolean isNoObjectType() {
return false;
}
@Override
public boolean isNoType() {
return true;
}
@Override
public boolean isNullable() {
return true;
}
@Override
public boolean isSubtype(JSType that) {
return true;
}
@Override
public JSType getLeastSupertype(JSType that) {
return that;
}
@Override
public JSType getGreatestSubtype(JSType that) {
if (that.isUnknownType()) {
return registry.getNativeType(JSTypeNative.UNKNOWN_TYPE);
}
return this;
}
@Override
public BooleanLiteralSet getPossibleToBooleanOutcomes() {
return BooleanLiteralSet.EMPTY;
}
@Override
public boolean matchesNumberContext() {
return true;
}
@Override
public boolean matchesObjectContext() {
return true;
}
@Override
public boolean matchesStringContext() {
return true;
}
@Override
public <T> T visit(Visitor<T> visitor) {
return visitor.caseNoType();
}
@Override
public String toString() {
return "None";
}
}
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS> collection of elements. Each element
* is referenced by its name, and has an {@link EnumElementType} type.
*
*
*/
public class EnumType extends PrototypeObjectType {
private static final long serialVersionUID = 1L;
// the type of the individual elements
private EnumElementType elementsType;
// the elements' names (they all have the same type)
private final Set<String> elements = new HashSet<String>();
/**
* Creates an enum type.
*
* @param name the enum's name
* @param elementsType the base type of the individual elements
*/
EnumType(JSTypeRegistry registry, String name, JSType elementsType) {
super(registry, "enum{" + name + "}", null);
this.elementsType = new EnumElementType(registry, elementsType, name);
}
@Override
public boolean isEnumType() {
return true;
}
@Override
public ObjectType getImplicitPrototype() {
return registry.getNativeObjectType(JSTypeNative.OBJECT_TYPE);
}
/**
* Gets the elements defined on this enum.
* @return the elements' names defined on this enum. The returned set is
* immutable.
*/
public Set<String> getElements() {
return Collections.unmodifiableSet(elements);
}
public boolean defineElement(String name) {
elements.add(name);
return defineDeclaredProperty(name, elementsType, false);
}
/**
* Gets the elements' type.
*/
public EnumElementType getElementsType() {
return elementsType;
}
@Override
public TernaryValue testForEquality(JSType that) {
TernaryValue result = super.testForEquality(that);
if (result != null) {
return result;
}
return this.equals(that) ? TRUE : FALSE;
}
@Override
public boolean isSubtype(JSType that) {
return that.equals(getNativeType(JSTypeNative.OBJECT_TYPE)) ||
that.equals(getNativeType(JSTypeNative.OBJECT_PROTOTYPE)) ||
JSType.isSubtype(this, that);
}
@Override
public String toString() {
return getReferenceName();
}
@Override
public <T> T visit(Visitor<T> visitor) {
return visitor.
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>Type;
ParameterizedType(
JSTypeRegistry registry, ObjectType objectType, JSType parameterType) {
super(registry, objectType);
this.parameterType = parameterType;
}
@Override
public JSType getParameterType() {
return parameterType;
}
}
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS> static final long serialVersionUID = 1L;
ObjectType referencedType;
ProxyObjectType(JSTypeRegistry registry, ObjectType referencedType) {
super(registry);
this.referencedType = referencedType;
}
@Override
public String getReferenceName() {
return referencedType.getReferenceName();
}
@Override
public boolean hasReferenceName() {
return referencedType.hasReferenceName();
}
@Override public boolean matchesNumberContext() {
return referencedType.matchesNumberContext();
}
@Override
public boolean matchesStringContext() {
return referencedType.matchesStringContext();
}
@Override public boolean matchesObjectContext() {
return referencedType.matchesObjectContext();
}
@Override
public boolean canBeCalled() {
return referencedType.canBeCalled();
}
@Override
public boolean isUnknownType() {
return referencedType.isUnknownType();
}
@Override
public boolean isCheckedUnknownType() {
return referencedType.isCheckedUnknownType();
}
@Override
public boolean isNullable() {
return referencedType.isNullable();
}
@Override
public boolean isFunctionPrototypeType() {
return referencedType.isFunctionPrototypeType();
}
@Override
public boolean isEnumType() {
return referencedType.isEnumType();
}
@Override
public boolean isEnumElementType() {
return referencedType.isEnumElementType();
}
@Override
public boolean isConstructor() {
return referencedType.isConstructor();
}
@Override
public boolean isNominalType() {
return referencedType.isNominalType();
}
@Override
public boolean isInstanceType() {
return referencedType.isInstanceType();
}
@Override
public boolean isInterface() {
return referencedType.isInterface();
}
@Override
public boolean isOrdinaryFunction() {
return referencedType.isOrdinaryFunction();
}
@Override
public TernaryValue testForEquality(JSType that) {
return referencedType.testForEquality(that);
}
@Override
public boolean isSubtype(JSType that) {
return referencedType.isSubtype(that);
}
@Override
public Iterable<ObjectType> getCtorImplementedInterfaces() {
return referencedType.getCtorImplementedInterfaces();
}
@Override
public boolean canAssignTo(JSType that
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>/*
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1997-1999
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Bob Jervis
* Google Inc.
*
* Alternatively, the contents of this file may be used under the terms of
* the GNU General Public License Version 2 or later (the "GPL"), in which
* case the provisions of the GPL are applicable instead of those above. If
* you wish to allow use of your version of this file only under the terms of
* the GPL and not to allow others to use your version of this file under the
* MPL, indicate your decision by deleting the provisions above and replacing
* them with the notice and other provisions required by the GPL. If you do
* not delete the provisions above, a recipient may use your version of this
* file under either the MPL or the GPL.
*
* ***** END LICENSE BLOCK ***** */
package com.google.javascript.rhino.jstype;
import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.Token;
/**
* A builder for the Rhino Node representing Function parameters.
*
*/
public class FunctionParamBuilder {
private final JSTypeRegistry registry;
private final Node root = new Node(Token.LP);
public FunctionParamBuilder(JSTypeRegistry registry) {
this.registry =
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS> registry;
}
/**
* Add parameters of the given type to the end of the param list.
* @return False if this is called after optional params are added.
*/
public boolean addRequiredParams(JSType ...types) {
if (hasOptionalOrVarArgs()) {
return false;
}
for (JSType type : types) {
newParameter(type);
}
return true;
}
/**
* Add optional parameters of the given type to the end of the param list.
* @param types Types for each optional parameter. The builder will make them
* undefineable.
* @return False if this is called after var args are added.
*/
public boolean addOptionalParams(JSType ...types) {
if (hasVarArgs()) {
return false;
}
for (JSType type : types) {
newParameter(registry.createOptionalType(type)).setOptionalArg(true);
}
return true;
}
/**
* Add variable arguments to the end of the parameter list.
* @return False if this is called after var args are added.
*/
public boolean addVarArgs(JSType type) {
if (hasVarArgs()) {
return false;
}
// There are two types of variable argument functions:
// 1) Programmer-defined var args
// 2) Native bottom types that can accept any argument.
// For the first one, "undefined" is a valid value for all arguments.
// For the second, we do not want to cast it up to undefined.
if (!type.isEmptyType()) {
type = registry.createOptionalType(type);
}
newParameter(type).setVarArgs(true);
return true;
}
/**
* Copies the parameter specification from the given node.
*/
public void newParameterFromNode(Node n) {
Node newParam = newParameter(n.getJSType());
newParam.setVarArgs(n.isVarArgs());
newParam.setOptionalArg(n.isOptionalArg());
}
// Add a parameter to the list with the given type.
private Node newParameter(JSType type) {
Node paramNode = Node.newString(Token.NAME, "");
paramNode.setJSType(type);
root.addChildTo
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>ator and delegate base.
*/
public void applyDelegateRelationship(
ObjectType delegateSuperclass, ObjectType delegateBase,
ObjectType delegator, FunctionType delegateProxy,
FunctionType findDelegate);
/**
* @return the name of the delegate superclass.
*/
public String getDelegateSuperclassName();
/**
* Defines the delegate proxy properties. Their types depend on properties of
* the delegate base methods.
*/
public void defineDelegateProxyProperties(
JSTypeRegistry registry, Scope scope,
Map<ObjectType, ObjectType> delegateProxyMap);
/**
* Gets the name of the global object.
*/
public String getGlobalObject();
/**
* Whether this CALL function is testing for the existence of a property.
*/
public boolean isPropertyTestFunction(Node call);
/**
* Checks if the given method performs a object literal cast, and if it does,
* returns information on the cast. By default, always returns null. Meant
* to be overridden by subclasses.
*
* @param t The node traversal.
* @param callNode A CALL node.
*/
public ObjectLiteralCast getObjectLiteralCast(NodeTraversal t,
Node callNode);
static enum SubclassType {
INHERITS,
MIXIN
}
static class SubclassRelationship {
final SubclassType type;
final Node subclassNode;
final Node superclassNode;
final String subclassName;
final String superclassName;
SubclassRelationship(SubclassType type,
Node subclassNode, Node superclassNode) {
this.type = type;
this.subclassNode = subclassNode;
this.superclassNode = superclassNode;
this.subclassName = subclassNode.getQualifiedName();
this.superclassName = superclassNode.getQualifiedName();
}
}
/**
* Delegates provides a mechanism and structure for identifying where classes
* can call out to optional code to augment their functionality. The optional
* code is isolated from the base code through the use of a subclass in the
* optional code derived from the delegate class in the base code.
*/
static class DelegateRelationship {
/** The subclass in the base code. */
final String delegateBase;
/** The class in the base code. */
final String delegator;
DelegateRelationship(String delegateBase, String delegator) {
this.delegateBase = delegateBase;
this.
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS> which the
* code is specifically designed to work with multiple input types. Because
* JavaScript always knows the runtime type of an object value, this is safer
* than a C union.<p>
*
* For instance, values of the union type {@code (String,boolean)} can be of
* type {@code String} or of type {@code boolean}. The commutativity of the
* statement is captured by making {@code (String,boolean)} and
* {@code (boolean,String)} equal.<p>
*
* The implementation of this class prevents the creation of nested
* unions.<p>
*/
public class UnionType extends JSType {
private static final long serialVersionUID = 1L;
Set<JSType> alternates;
/**
* Creates a union type.
*
* @param alternates the alternates of the union
*/
UnionType(JSTypeRegistry registry, Set<JSType> alternates) {
super(registry);
this.alternates = alternates;
}
/**
* Gets the alternate types of this union type.
* @return The alternate types of this union type. The returned set is
* immutable.
*/
public Iterable<JSType> getAlternates() {
return alternates;
}
@Override
public void forgiveUnknownNames() {
for (JSType type : getAlternates()) {
type.forgiveUnknownNames();
}
}
/**
* This predicate is used to test whether a given type can appear in a
* numeric context, such as an operand of a multiply operator.
*
* @return true if the type can appear in a numeric context.
*/
@Override
public boolean matchesNumberContext() {
// TODO(user): Reverse this logic to make it correct instead of generous.
for (JSType t : alternates) {
if (t.matchesNumberContext()) {
return true;
}
}
return false;
}
/**
* This predicate is used to test whether a given type can appear in a
* {@code String} context, such as an operand of a string concat ({@code +})
* operator.<p>
*
* All types have at least the potential for converting to {@code String}.
* When we add externally defined types, such as a browser OM
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS> {
return true;
}
canAssign &= t.canAssignTo(that);
}
return canAssign;
}
@Override
public boolean canBeCalled() {
for (JSType t : alternates) {
if (!t.canBeCalled()) {
return false;
}
}
return true;
}
@Override
public JSType restrictByNotNullOrUndefined() {
UnionTypeBuilder restricted = new UnionTypeBuilder(registry);
for (JSType t : alternates) {
restricted.addAlternate(t.restrictByNotNullOrUndefined());
}
return restricted.build();
}
@Override
public TernaryValue testForEquality(JSType that) {
TernaryValue result = null;
for (JSType t : alternates) {
TernaryValue test = t.testForEquality(that);
if (result == null) {
result = test;
} else if (!result.equals(test)) {
return UNKNOWN;
}
}
return result;
}
/**
* This predicate determines whether objects of this type can have the
* {@code null} value, and therefore can appear in contexts where
* {@code null} is expected.
*
* @return {@code true} for everything but {@code Number} and
* {@code Boolean} types.
*/
@Override
public boolean isNullable() {
for (JSType t : alternates) {
if (t.isNullable()) {
return true;
}
}
return false;
}
@Override
public boolean isUnknownType() {
for (JSType t : alternates) {
if (t.isUnknownType()) {
return true;
}
}
return false;
}
@Override
public JSType getLeastSupertype(JSType that) {
if (!that.isUnknownType()) {
for (JSType alternate : alternates) {
if (!alternate.isUnknownType() && that.isSubtype(alternate)) {
return this;
}
}
}
return getLeastSupertype(this, that);
}
JSType meet(JSType that) {
UnionTypeBuilder builder = new UnionTypeBuilder(registry);
for (JSType alternate : alternates) {
if (alternate.isSubtype(that)) {
builder
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>
* <li>{@code (null, EvalError, URIError)} restricted by
* {@code Error} is {@code null}</li>
* </ul>
*
* @param type the supertype of the types to remove from this union type
*/
public JSType getRestrictedUnion(JSType type) {
UnionTypeBuilder restricted = new UnionTypeBuilder(registry);
for (JSType t : alternates) {
if (t.isUnknownType() || !t.isSubtype(type)) {
restricted.addAlternate(t);
}
}
return restricted.build();
}
@Override public String toString() {
StringBuilder result = new StringBuilder();
boolean firstAlternate = true;
result.append("(");
SortedSet<JSType> sorted = new TreeSet<JSType>(ALPHA);
sorted.addAll(alternates);
for (JSType t : sorted) {
if (!firstAlternate) {
result.append("|");
}
result.append(t.toString());
firstAlternate = false;
}
result.append(")");
return result.toString();
}
@Override
public boolean isSubtype(JSType that) {
for (JSType element : alternates) {
if (!element.isSubtype(that)) {
return false;
}
}
return true;
}
@Override
public JSType getRestrictedTypeGivenToBooleanOutcome(boolean outcome) {
// gather elements after restriction
UnionTypeBuilder restricted = new UnionTypeBuilder(registry);
for (JSType element : alternates) {
restricted.addAlternate(
element.getRestrictedTypeGivenToBooleanOutcome(outcome));
}
return restricted.build();
}
@Override
public BooleanLiteralSet getPossibleToBooleanOutcomes() {
BooleanLiteralSet literals = BooleanLiteralSet.EMPTY;
for (JSType element : alternates) {
literals = literals.union(element.getPossibleToBooleanOutcomes());
if (literals == BooleanLiteralSet.BOTH) {
break;
}
}
return literals;
}
@Override
public TypePair getTypesUnderEquality(JSType that) {
UnionTypeBuilder thisRestricted = new UnionTypeBuilder(registry);
UnionTypeBuilder thatRestricted = new UnionTypeBuilder(registry);
for (JSType element : alternates) {
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS> TypePair p = element.getTypesUnderEquality(that);
if (p.typeA != null) {
thisRestricted.addAlternate(p.typeA);
}
if (p.typeB != null) {
thatRestricted.addAlternate(p.typeB);
}
}
return new TypePair(
thisRestricted.build(),
thatRestricted.build());
}
@Override
public TypePair getTypesUnderInequality(JSType that) {
UnionTypeBuilder thisRestricted = new UnionTypeBuilder(registry);
UnionTypeBuilder thatRestricted = new UnionTypeBuilder(registry);
for (JSType element : alternates) {
TypePair p = element.getTypesUnderInequality(that);
if (p.typeA != null) {
thisRestricted.addAlternate(p.typeA);
}
if (p.typeB != null) {
thatRestricted.addAlternate(p.typeB);
}
}
return new TypePair(
thisRestricted.build(),
thatRestricted.build());
}
@Override
public TypePair getTypesUnderShallowInequality(JSType that) {
UnionTypeBuilder thisRestricted = new UnionTypeBuilder(registry);
UnionTypeBuilder thatRestricted = new UnionTypeBuilder(registry);
for (JSType element : alternates) {
TypePair p = element.getTypesUnderShallowInequality(that);
if (p.typeA != null) {
thisRestricted.addAlternate(p.typeA);
}
if (p.typeB != null) {
thatRestricted.addAlternate(p.typeB);
}
}
return new TypePair(
thisRestricted.build(),
thatRestricted.build());
}
@Override
public <T> T visit(Visitor<T> visitor) {
return visitor.caseUnionType(this);
}
@Override
JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) {
setResolvedTypeInternal(this); // for circularly defined types.
boolean changed = false;
ImmutableSet.Builder<JSType> resolvedTypes = ImmutableSet.builder();
for (JSType alternate : alternates) {
JSType newAlternate = alternate.resolve(t, scope);
changed |= (alternate != newAlternate);
resolvedTypes.add(alternate);
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>code>
* var x = function() {};
* if (x instanceof Array) {
* f(x);
* }
* </code>
* We need to be able to assign {@code x} a type within the {@code f(x)}
* call. It has no possible type, but {@code x} would not be legal if f
* expected a string. So we assign it the {@code NoObjectType}.
*
*
*
* @see <a href="http://en.wikipedia.org/wiki/Bottom_type">Bottom types</a>
*/
public class NoObjectType extends FunctionType {
private static final long serialVersionUID = 1L;
/**
* Visitor for {@link NoObjectType#getLeastSupertype(JSType)}.
*/
private final Visitor<JSType> leastSupertypeVisitor =
new LeastSupertypeVisitor();
private class LeastSupertypeVisitor implements Visitor<JSType>, Serializable {
private static final long serialVersionUID = 1L;
public JSType caseNoObjectType() {
return getNativeType(JSTypeNative.NO_OBJECT_TYPE);
}
public JSType caseUnknownType() {
return getNativeType(JSTypeNative.UNKNOWN_TYPE);
}
public JSType caseNoType() {
return getNativeType(JSTypeNative.NO_OBJECT_TYPE);
}
public JSType caseBooleanType() {
return registry.createUnionType(JSTypeNative.NO_OBJECT_TYPE,
JSTypeNative.BOOLEAN_TYPE);
}
public JSType caseFunctionType(FunctionType type) {
return type;
}
public JSType caseNullType() {
return registry.createUnionType(JSTypeNative.NO_OBJECT_TYPE,
JSTypeNative.NULL_TYPE);
}
public JSType caseNumberType() {
return registry.createUnionType(JSTypeNative.NO_OBJECT_TYPE,
JSTypeNative.NUMBER_TYPE);
}
public JSType caseObjectType(ObjectType type) {
return type;
}
public JSType caseStringType() {
return registry.createUnionType(JSTypeNative.NO_OBJECT_TYPE,
JSTypeNative.STRING_TYPE);
}
public JSType caseUnionType(UnionType type) {
return registry.createUnionType(
getNativeType(JS
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>TypeNative.NO_OBJECT_TYPE), type);
}
public JSType caseAllType() {
return getNativeType(JSTypeNative.ALL_TYPE);
}
public JSType caseVoidType() {
return registry.createUnionType(JSTypeNative.NO_OBJECT_TYPE,
JSTypeNative.VOID_TYPE);
}
public JSType caseEnumElementType(EnumElementType type) {
JSType primitive = type.getPrimitiveType();
return primitive.isObject() ? primitive :
registry.createUnionType(
getNativeType(JSTypeNative.NO_OBJECT_TYPE), type);
}
}
/**
* Visitor for {@link NoObjectType#getGreatestSubtype(JSType)}.
*/
private final Visitor<JSType> greatestSubtypeVisitor =
new GreatestSupertypeVisitor();
private class GreatestSupertypeVisitor
implements Visitor<JSType>, Serializable {
private static final long serialVersionUID = 1L;
public JSType caseNoObjectType() {
return getNativeType(JSTypeNative.NO_OBJECT_TYPE);
}
public JSType caseUnknownType() {
return getNativeType(JSTypeNative.UNKNOWN_TYPE);
}
public JSType caseNoType() {
return getNativeType(JSTypeNative.NO_TYPE);
}
public JSType caseBooleanType() {
return getNativeType(JSTypeNative.NO_TYPE);
}
public JSType caseFunctionType(FunctionType type) {
return getNativeType(JSTypeNative.NO_OBJECT_TYPE);
}
public JSType caseNullType() {
return getNativeType(JSTypeNative.NO_TYPE);
}
public JSType caseNumberType() {
return getNativeType(JSTypeNative.NO_TYPE);
}
public JSType caseObjectType(ObjectType type) {
return getNativeType(JSTypeNative.NO_OBJECT_TYPE);
}
public JSType caseStringType() {
return getNativeType(JSTypeNative.NO_TYPE);
}
public JSType caseUnionType(UnionType that) {
JSType anyObjectType = getNativeType(JSTypeNative.NO_OBJECT_TYPE);
if (anyObjectType.isSubtype(that)) {
return anyObjectType;
} else if (that.isSubtype(anyObjectType)) {
return that;
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS> } else {
return getNativeType(JSTypeNative.NO_TYPE);
}
}
public JSType caseAllType() {
return getNativeType(JSTypeNative.NO_OBJECT_TYPE);
}
public JSType caseVoidType() {
return getNativeType(JSTypeNative.NO_OBJECT_TYPE);
}
public JSType caseEnumElementType(EnumElementType type) {
return type.getPrimitiveType().visit(this);
}
}
NoObjectType(JSTypeRegistry registry) {
super(registry, null, null, null, null, null, null, true, true);
}
@Override
public JSType getReturnType() {
return this;
}
@Override
public ObjectType getInstanceType() {
return this;
}
@Override
public TernaryValue testForEquality(JSType that) {
return that.isEmptyType() ? TernaryValue.TRUE : TernaryValue.UNKNOWN;
}
@Override
public boolean isSubtype(JSType that) {
if (JSType.isSubtype(this, that)) {
return true;
} else {
return that.isObject() && !that.isNoType();
}
}
@Override
public boolean isFunctionType() {
return false;
}
@Override
public boolean isNoObjectType() {
return true;
}
@Override
public JSType getLeastSupertype(JSType that) {
return that.visit(leastSupertypeVisitor);
}
@Override
public JSType getGreatestSubtype(JSType that) {
return that.visit(greatestSubtypeVisitor);
}
@Override
public ObjectType getImplicitPrototype() {
return null;
}
@Override
public String getReferenceName() {
return null;
}
@Override
public boolean matchesNumberContext() {
return true;
}
@Override
public boolean matchesObjectContext() {
return true;
}
@Override
public boolean matchesStringContext() {
return true;
}
@Override
public boolean equals(Object that) {
return this == that;
}
@Override
public int hashCode() {
return System.identityHashCode(this);
}
@Override
public int getPropertiesCount() {
// Should never be called, returning the biggest number to highlight the
// '
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>ReporterParser parser = new ErrorReporterParser();
private class ErrorReporterParser {
void addWarning(String messageId, String messageArg, int lineno,
int charno) {
errorReporter.warning(ScriptRuntime.getMessage1(messageId, messageArg),
sourceName, lineno, null, charno);
}
void addWarning(String messageId, int lineno, int charno) {
errorReporter.warning(ScriptRuntime.getMessage0(messageId),
sourceName, lineno, null, charno);
}
}
// The DocInfo with the fileoverview tag for the whole file.
private JSDocInfo fileOverviewJSDocInfo = null;
private State state;
private final Map<String, Annotation> annotationNames;
private Node.FileLevelJsDocBuilder fileLevelJsDocBuilder;
/**
* Sets the JsDocBuilder for the file-level (root) node of this parse. The
* parser uses the builder to append any preserve annotations it encounters
* in jsdoc comments.
*
* @param fileLevelJsDocBuilder
*/
void setFileLevelJsDocBuilder(
Node.FileLevelJsDocBuilder fileLevelJsDocBuilder) {
this.fileLevelJsDocBuilder = fileLevelJsDocBuilder;
}
/**
* Sets the file overview JSDocInfo, in order to warn about multiple uses of
* the @fileoverview tag in a file.
*/
void setFileOverviewJSDocInfo(JSDocInfo fileOverviewJSDocInfo) {
this.fileOverviewJSDocInfo = fileOverviewJSDocInfo;
}
private enum State {
SEARCHING_ANNOTATION,
SEARCHING_NEWLINE,
NEXT_IS_ANNOTATION
}
JsDocInfoParser(JsDocTokenStream stream,
String sourceName,
Config config,
ErrorReporter errorReporter) {
this.stream = stream;
this.sourceName = sourceName;
this.typeRegistry = config.registry;
this.jsdocBuilder = new JSDocInfoBuilder(config.parseJsDocDocumentation);
this.annotationNames = config.annotationNames;
this.errorReporter = errorReporter;
}
/**
* Parses a string containing a JsDoc type declaration, returning the
* type if the parsing succeeded or {@code null} if it failed.
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>Call(Node callNode) {
return null;
}
@Override
public boolean isSuperClassReference(String propertyName) {
return false;
}
@Override
public String extractClassNameIfProvide(Node node, Node parent) {
String message = "only implemented in GoogleCodingConvention";
throw new UnsupportedOperationException(message);
}
@Override
public String extractClassNameIfRequire(Node node, Node parent) {
String message = "only implemented in GoogleCodingConvention";
throw new UnsupportedOperationException(message);
}
@Override
public String getExportPropertyFunction() {
return null;
}
@Override
public String getExportSymbolFunction() {
return null;
}
@Override
public List<String> identifyTypeDeclarationCall(Node n) {
return null;
}
@Override
public String identifyTypeDefAssign(Node n) {
return null;
}
@Override
public void applySubclassRelationship(FunctionType parentCtor,
FunctionType childCtor, SubclassType type) {
// do nothing
}
@Override
public String getAbstractMethodName() {
return null;
}
@Override
public String getSingletonGetterClassName(Node callNode) {
return null;
}
@Override
public void applySingletonGetter(FunctionType functionType,
FunctionType getterType, ObjectType objectType) {
// do nothing.
}
@Override
public DelegateRelationship getDelegateRelationship(Node callNode) {
return null;
}
@Override
public void applyDelegateRelationship(
ObjectType delegateSuperclass, ObjectType delegateBase,
ObjectType delegator, FunctionType delegateProxy,
FunctionType findDelegate) {
// do nothing.
}
@Override
public String getDelegateSuperclassName() {
return null;
}
@Override
public void defineDelegateProxyProperties(
JSTypeRegistry registry, Scope scope,
Map<ObjectType, ObjectType> delegateProxyMap) {
// do nothing.
}
@Override
public String getGlobalObject() {
return "window";
}
@Override
public boolean isPropertyTestFunction(Node call) {
return false;
}
@Override
public ObjectLiteralCast getObjectLiteralCast(NodeTraversal t,
Node callNode) {
return null;
}
}
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS> abstract T processSwitchCase(SwitchCase caseNode);
abstract T processSwitchStatement(SwitchStatement statementNode);
abstract T processThrowStatement(ThrowStatement statementNode);
abstract T processTryStatement(TryStatement statementNode);
abstract T processUnaryExpression(UnaryExpression exprNode);
abstract T processVariableDeclaration(VariableDeclaration declarationNode);
abstract T processVariableInitializer(VariableInitializer initializerNode);
abstract T processWhileLoop(WhileLoop loopNode);
abstract T processWithStatement(WithStatement statementNode);
abstract T processIllegalToken(AstNode node);
public T process(AstNode node) {
switch (node.getType()) {
case Token.ADD:
case Token.AND:
case Token.BITAND:
case Token.BITOR:
case Token.BITXOR:
case Token.COMMA:
case Token.DIV:
case Token.EQ:
case Token.GE:
case Token.GT:
case Token.IN:
case Token.INSTANCEOF:
case Token.LE:
case Token.LSH:
case Token.LT:
case Token.MOD:
case Token.MUL:
case Token.NE:
case Token.OR:
case Token.RSH:
case Token.SHEQ:
case Token.SHNE:
case Token.SUB:
case Token.URSH:
return processInfixExpression((InfixExpression) node);
case Token.ARRAYLIT:
return processArrayLiteral((ArrayLiteral) node);
case Token.ASSIGN:
case Token.ASSIGN_ADD:
case Token.ASSIGN_BITAND:
case Token.ASSIGN_BITOR:
case Token.ASSIGN_BITXOR:
case Token.ASSIGN_DIV:
case Token.ASSIGN_LSH:
case Token.ASSIGN_MOD:
case Token.ASSIGN_MUL:
case Token.ASSIGN_RSH:
case Token.ASSIGN_SUB:
case Token.ASSIGN_URSH:
return processAssignment((Assignment) node);
case Token.BITNOT:
case Token.DEC:
case Token.DELPROP:
case Token.INC:
case Token.NEG:
case Token.NOT:
case Token.POS:
case Token.TYPEOF:
case Token.VOID:
return processUnaryExpression((UnaryExpression) node);
case Token.BLOCK:
if (node instanceof Block
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>SimpleOperatorType(int type) {
switch (type) {
case Token.ADD:
case Token.BITAND:
case Token.BITNOT:
case Token.BITOR:
case Token.BITXOR:
case Token.COMMA:
case Token.DIV:
case Token.EQ:
case Token.GE:
case Token.GETELEM:
case Token.GETPROP:
case Token.GT:
case Token.INSTANCEOF:
case Token.LE:
case Token.LSH:
case Token.LT:
case Token.MOD:
case Token.MUL:
case Token.NE:
case Token.NOT:
case Token.RSH:
case Token.SHEQ:
case Token.SHNE:
case Token.SUB:
case Token.TYPEOF:
case Token.VOID:
case Token.POS:
case Token.NEG:
case Token.URSH:
return true;
default:
return false;
}
}
/**
* Creates an EXPR_RESULT.
*
* @param child The expression itself.
* @return Newly created EXPR node with the child as subexpression.
*/
public static Node newExpr(Node child) {
return new Node(Token.EXPR_RESULT, child);
}
/**
* Returns true if the node may create new mutable state, or change existing
* state.
*
* @see <a href="http://www.xkcd.org/326/">XKCD Cartoon</a>
*/
static boolean mayEffectMutableState(Node n) {
return checkForStateChangeHelper(n, true);
}
/**
* Returns true if the node which may have side effects when executed.
*/
static boolean mayHaveSideEffects(Node n) {
return checkForStateChangeHelper(n, false);
}
/**
* Returns true if some node in n's subtree changes application state.
* If {@code checkForNewObjects} is true, we assume that newly created
* mutable objects (like object literals) change state. Otherwise, we assume
* that they have no side effects.
*/
private static boolean checkForStateChangeHelper(
Node n, boolean checkForNewObjects) {
// Rather than id which ops may have side effects, id the ones
// that we
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>BITAND: return 7;
case Token.EQ:
case Token.NE:
case Token.SHEQ:
case Token.SHNE: return 8;
case Token.LT:
case Token.GT:
case Token.LE:
case Token.GE:
case Token.INSTANCEOF:
case Token.IN: return 9;
case Token.LSH:
case Token.RSH:
case Token.URSH: return 10;
case Token.SUB:
case Token.ADD: return 11;
case Token.MUL:
case Token.MOD:
case Token.DIV: return 12;
case Token.INC:
case Token.DEC:
case Token.NEW:
case Token.DELPROP:
case Token.TYPEOF:
case Token.VOID:
case Token.NOT:
case Token.BITNOT:
case Token.POS:
case Token.NEG: return 13;
case Token.ARRAYLIT:
case Token.CALL:
case Token.EMPTY:
case Token.FALSE:
case Token.FUNCTION:
case Token.GETELEM:
case Token.GETPROP:
case Token.GET_REF:
case Token.IF:
case Token.LP:
case Token.NAME:
case Token.NULL:
case Token.NUMBER:
case Token.OBJECTLIT:
case Token.REGEXP:
case Token.RETURN:
case Token.STRING:
case Token.THIS:
case Token.TRUE:
return 15;
default: throw new Error("Unknown precedence for " +
Node.tokenToName(type) +
" (type " + type + ")");
}
}
/**
* Returns true if the operator is associative.
* e.g. (a * b) * c = a * (b * c)
* Note: "+" is not associative because it is also the concatentation
* for strings. e.g. "a" + (1 + 2) is not "a" + 1 + 2
*/
static boolean isAssociative(int type) {
switch (type) {
case Token.MUL:
case Token.AND:
case Token.OR:
case Token.BITOR:
case Token
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS> case Token.MOD: return "%";
case Token.BITNOT: return "~";
case Token.ADD: return "+";
case Token.SUB: return "-";
case Token.POS: return "+";
case Token.NEG: return "-";
case Token.ASSIGN: return "=";
case Token.ASSIGN_BITOR: return "|=";
case Token.ASSIGN_BITXOR: return "^=";
case Token.ASSIGN_BITAND: return "&=";
case Token.ASSIGN_LSH: return "<<=";
case Token.ASSIGN_RSH: return ">>=";
case Token.ASSIGN_URSH: return ">>>=";
case Token.ASSIGN_ADD: return "+=";
case Token.ASSIGN_SUB: return "-=";
case Token.ASSIGN_MUL: return "*=";
case Token.ASSIGN_DIV: return "/=";
case Token.ASSIGN_MOD: return "%=";
case Token.VOID: return "void";
case Token.TYPEOF: return "typeof";
case Token.INSTANCEOF: return "instanceof";
default: return null;
}
}
/**
* Converts an operator's token value (see {@link Token}) to a string
* representation or fails.
*
* @param operator the operator's token value to convert
* @return the string representation
* @throws Error if the token value is not an operator
*/
static String opToStrNoFail(int operator) {
String res = opToStr(operator);
if (res == null) {
throw new Error("Unknown op " + operator + ": " +
Token.name(operator));
}
return res;
}
/**
* @return true if n or any of its children are of the specified type.
* Does not traverse into functions.
*/
static boolean containsTypeInOuterScope(Node node, int type) {
return containsType(node, type,
Predicates.<Node>not(new NodeUtil.MatchNodeType(Token.FUNCTION)));
}
/**
* @return true if n or any of its children are of the specified type
*/
static boolean containsType(Node node,
int type,
Predicate<Node> traverseChildrenPred) {
return has(node, new MatchNodeType(type), traverseChildrenPred);
}
/**
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>ertype of a record type
* of the form { b : TYPE_2, a : TYPE_1 } because B can be assigned to
* A and matches all constraints. Similarly, a defined type can be assigned
* to a record type so long as that defined type matches all property
* constraints of the record type. A record type of the form { a : A, b : B }
* can be assigned to a record of type { a : A }.
*
*
*/
public class RecordType extends PrototypeObjectType {
private static final long serialVersionUID = 1L;
private Map<String, JSType> properties = new HashMap<String, JSType>();
private boolean isFrozen = false;
/**
* Creates a record type.
*
* @param registry The type registry under which this type lives.
* @param properties A map of all the properties of this record type.
*/
RecordType(JSTypeRegistry registry, Map<String, JSType> properties) {
super(registry, null, null);
for (String property : properties.keySet()) {
defineDeclaredProperty(property, properties.get(property), false);
}
// Freeze the record type.
isFrozen = true;
}
@Override
public boolean equals(Object other) {
if (!(other instanceof RecordType)) {
return false;
}
// Compare properties.
RecordType otherRecord = (RecordType) other;
return otherRecord.properties.equals(properties);
}
@Override
public ObjectType getImplicitPrototype() {
return registry.getNativeObjectType(JSTypeNative.OBJECT_TYPE);
}
@Override
boolean defineProperty(String propertyName, JSType type,
boolean inferred, boolean inExterns) {
if (isFrozen) {
return false;
}
if (!inferred) {
properties.put(propertyName, type);
}
return super.defineProperty(propertyName, type, inferred, inExterns);
}
@Override
public JSType getLeastSupertype(JSType that) {
if (!that.isRecordType()) {
return super.getLeastSupertype(that);
}
RecordType thatRecord = (RecordType) that;
RecordTypeBuilder builder = new RecordTypeBuilder(registry);
// The least supertype consist of those properties of the record
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS> // type that both record types hold in common both by name and
// type of the properties themselves.
for (String property : properties.keySet()) {
if (thatRecord.hasProperty(property) &&
thatRecord.getPropertyType(property).equals(
getPropertyType(property))) {
builder.addProperty(property, getPropertyType(property));
}
}
return builder.build();
}
@Override
public JSType getGreatestSubtype(JSType that) {
if (that.isRecordType()) {
RecordType thatRecord = (RecordType) that;
RecordTypeBuilder builder = new RecordTypeBuilder(registry);
// The greatest subtype consists of those *unique* properties of both
// record types. If any property conflicts, then the NO_TYPE type
// is returned.
for (String property : properties.keySet()) {
if (thatRecord.hasProperty(property) &&
!thatRecord.getPropertyType(property).equals(
getPropertyType(property))) {
return registry.getNativeObjectType(JSTypeNative.NO_TYPE);
}
builder.addProperty(property, getPropertyType(property));
}
for (String property : thatRecord.properties.keySet()) {
if (!hasProperty(property)) {
builder.addProperty(property, thatRecord.getPropertyType(property));
}
}
return builder.build();
}
JSType greatestSubtype = super.getGreatestSubtype(that);
if (greatestSubtype.isNoObjectType() && !that.isNoObjectType()) {
// In this branch, the other type is some object type. We find
// the greatest subtype with the following algorithm:
// 1) For each property "x" of this record type, take the union
// of all classes with a property "x" with a compatible property type.
// and which are a subtype of {@code that}.
// 2) Take the intersection of all of these unions.
for (Map.Entry<String, JSType> entry : properties.entrySet()) {
String propName = entry.getKey();
JSType propType = entry.getValue();
UnionTypeBuilder builder = new UnionTypeBuilder(registry);
for (ObjectType alt : registry.getTypesWithProperty(propName)) {
JSType altPropType = alt.getPropertyType(propName);
if (
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>altPropType != null && !alt.equals(this) &&
alt.isSubtype(that) &&
(propType.isUnknownType() || altPropType.isUnknownType() ||
altPropType.equals(propType))) {
builder.addAlternate(alt);
}
}
greatestSubtype = greatestSubtype.getLeastSupertype(builder.build());
}
}
return greatestSubtype;
}
@Override
public boolean isRecordType() {
return true;
}
@Override
public boolean isSubtype(JSType that) {
if (JSType.isSubtype(this, that)) {
return true;
}
// Top of the record types is the empty record, or OBJECT_TYPE.
if (registry.getNativeObjectType(
JSTypeNative.OBJECT_TYPE).isSubtype(that)) {
return true;
}
// A type is a subtype of a record type if it itself is a record
// type and it has at least the same members as the parent record type
// with the same types.
if (!that.isRecordType()) {
return false;
}
return RecordType.isSubtype(this, (RecordType) that);
}
/** Determines if typeA is a subtype of typeB */
static boolean isSubtype(ObjectType typeA, RecordType typeB) {
// typeA is a subtype of record type typeB iff:
// 1) typeA has all the properties declared in typeB.
// 2) And for each property of typeB,
// 2a) if the property of typeA is declared, it must be equal
// to the type of the property of typeB,
// 2b) otherwise, it must be a subtype of the property of typeB.
//
// To figure out why this is true, consider the following pseudo-code:
// /** @type {{a: (Object,null)}} */ var x;
// /** @type {{a: !Object}} */ var y;
// var z = {a: {}};
// x.a = null;
//
// y cannot be assigned to x, because line 4 would violate y's declared
// properties. But z can be assigned to x. Even though z and y are the
// same type, the properties of z are inferred--
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>/*
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1997-1999
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Bob Jervis
* Google Inc.
*
* Alternatively, the contents of this file may be used under the terms of
* the GNU General Public License Version 2 or later (the "GPL"), in which
* case the provisions of the GPL are applicable instead of those above. If
* you wish to allow use of your version of this file only under the terms of
* the GPL and not to allow others to use your version of this file under the
* MPL, indicate your decision by deleting the provisions above and replacing
* them with the notice and other provisions required by the GPL. If you do
* not delete the provisions above, a recipient may use your version of this
* file under either the MPL or the GPL.
*
* ***** END LICENSE BLOCK ***** */
package com.google.javascript.rhino.jstype;
import static com.google.javascript.rhino.jstype.JSTypeNative.ALL_TYPE;
/**
* This type is for built-in error constructors.
*
*
*/
class ErrorFunctionType extends FunctionType {
private static final long serialVersionUID = 1L;
ErrorFunctionType(JSTypeRegistry registry, String name) {
super(registry, name, null,
registry.createOptionalParameters(
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>
registry.getNativeType(ALL_TYPE),
registry.getNativeType(ALL_TYPE),
registry.getNativeType(ALL_TYPE)),
null, null, null, true, true);
}
@Override
public JSType getReturnType() {
return getInstanceType();
}
}
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>/*
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1997-1999
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Bob Jervis
* Google Inc.
*
* Alternatively, the contents of this file may be used under the terms of
* the GNU General Public License Version 2 or later (the "GPL"), in which
* case the provisions of the GPL are applicable instead of those above. If
* you wish to allow use of your version of this file only under the terms of
* the GPL and not to allow others to use your version of this file under the
* MPL, indicate your decision by deleting the provisions above and replacing
* them with the notice and other provisions required by the GPL. If you do
* not delete the provisions above, a recipient may use your version of this
* file under either the MPL or the GPL.
*
* ***** END LICENSE BLOCK ***** */
package com.google.javascript.rhino.jstype;
import static com.google.javascript.rhino.jstype.TernaryValue.UNKNOWN;
import com.google.javascript.rhino.ErrorReporter;
/**
* All type, representing all values.
*
*
*/
public final class AllType extends JSType {
private static final long serialVersionUID = 1L;
AllType(JSTypeRegistry registry) {
super(registry);
}
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS> /**
* The All type is the greatest type (top) and is never a subtype of
* another except itself or the Unknown type.
* @return {@code this.equals(that)}
*/
@Override
public boolean isSubtype(JSType that) {
return that.isAllType() || that.isUnknownType();
}
@Override
public boolean isAllType() {
return true;
}
@Override
public boolean matchesStringContext() {
// Be lenient.
return true;
}
@Override
public boolean matchesObjectContext() {
// Be lenient.
return true;
}
@Override
public boolean canBeCalled() {
return false;
}
@Override
public TernaryValue testForEquality(JSType that) {
return UNKNOWN;
}
@Override
public JSType getLeastSupertype(JSType that) {
if (that.isUnknownType()) {
return registry.getNativeType(JSTypeNative.UNKNOWN_TYPE);
}
return this;
}
@Override
public JSType getGreatestSubtype(JSType that) {
return that;
}
@Override
public String toString() {
return "*";
}
@Override
public <T> T visit(Visitor<T> visitor) {
return visitor.caseAllType();
}
@Override
public BooleanLiteralSet getPossibleToBooleanOutcomes() {
return BooleanLiteralSet.BOTH;
}
@Override
JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) {
return this;
}
}
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>import static com.google.javascript.rhino.jstype.JSTypeNative.NO_TYPE;
import static com.google.javascript.rhino.jstype.JSTypeNative.UNKNOWN_TYPE;
import java.io.Serializable;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
/**
* A builder for union types.
*
*
*/
class UnionTypeBuilder implements Serializable {
private static final long serialVersionUID = 1L;
// If the best we can do is say "this object is one of twenty things",
// then we should just give up and admit that we have no clue.
private static final int MAX_UNION_SIZE = 20;
private final JSTypeRegistry registry;
private final List<JSType> alternates = Lists.newArrayList();
private boolean isAllType = false;
private boolean isNativeUnknownType = false;
private boolean areAllUnknownsChecked = true;
// Memoize the result, in case build() is called multiple times.
private JSType result = null;
UnionTypeBuilder(JSTypeRegistry registry) {
this.registry = registry;
}
/**
* Adds an alternate to the union type under construction. Returns this
* for easy chaining.
*/
UnionTypeBuilder addAlternate(JSType alternate) {
// build() returns the bottom type by default, so we can
// just bail out early here.
if (alternate.isNoType()) {
return this;
}
isAllType = isAllType || alternate.isAllType();
boolean isAlternateUnknown = alternate instanceof UnknownType;
isNativeUnknownType = isNativeUnknownType || isAlternateUnknown;
if (isAlternateUnknown) {
areAllUnknownsChecked = areAllUnknownsChecked &&
alternate.isCheckedUnknownType();
}
if (!isAllType && !isNativeUnknownType) {
if (alternate instanceof UnionType) {
UnionType union = (UnionType) alternate;
for (JSType unionAlt : union.getAlternates()) {
addAlternate(unionAlt);
}
} else {
if (!alternate.isUnknownType()) {
Iterator<JSType> it = alternates.iterator();
while (it.hasNext()) {
JSType current = it.next();
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>
if (!current.isUnknownType()) {
if (alternate.isSubtype(current)) {
// Alternate is unnecessary.
return this;
} else if (current.isSubtype(alternate)) {
// Alternate makes current obsolete
it.remove();
}
}
}
}
alternates.add(alternate);
result = null; // invalidate the memoized result
}
} else {
result = null;
}
return this;
}
/**
* Creates a union.
* @return A UnionType if it has two or more alternates, the
* only alternate if it has one and otherwise {@code NO_TYPE}.
*/
JSType build() {
if (result == null) {
if (isAllType) {
result = registry.getNativeType(ALL_TYPE);
} else if (isNativeUnknownType) {
if (areAllUnknownsChecked) {
result = registry.getNativeType(CHECKED_UNKNOWN_TYPE);
} else {
result = registry.getNativeType(UNKNOWN_TYPE);
}
} else {
Set<JSType> alternateSet = Sets.newUnmodifiableHashSet(alternates);
int size = alternateSet.size();
if (size > MAX_UNION_SIZE) {
result = registry.getNativeType(UNKNOWN_TYPE);
} else {
if (size > 1) {
result = new UnionType(registry, alternateSet);
} else if (size == 1) {
result = alternates.iterator().next();
} else {
result = registry.getNativeType(NO_TYPE);
}
}
}
}
return result;
}
}
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS> defining the {@code LOCAL_CODES} enum
* <pre>var LOCAL_CODES = {A: 3, B: 9, C: 8}</pre>
* the primitive type of the the constants is {@code number}.
*/
private JSType primitiveType;
// The primitive type, if it is an object.
private ObjectType primitiveObjectType;
private final String name;
EnumElementType(JSTypeRegistry registry, JSType elementType,
String name) {
super(registry);
this.primitiveType = elementType;
this.primitiveObjectType = elementType.toObjectType();
this.name = name;
}
@Override
public boolean isEnumElementType() {
return true;
}
@Override
public boolean matchesNumberContext() {
return primitiveType.matchesNumberContext();
}
@Override
public boolean matchesStringContext() {
return primitiveType.matchesStringContext();
}
@Override
public boolean matchesObjectContext() {
return primitiveType.matchesObjectContext();
}
@Override
public boolean canBeCalled() {
return primitiveType.canBeCalled();
}
@Override
public boolean isObject() {
return primitiveType.isObject();
}
@Override
public TernaryValue testForEquality(JSType that) {
return primitiveType.testForEquality(that);
}
/**
* This predicate determines whether objects of this type can have the null
* value, and therefore can appear in contexts where null is expected.
*
* @return true for everything but Number and Boolean types.
*/
@Override public boolean isNullable() {
return primitiveType.isNullable();
}
@Override
public boolean isNominalType() {
return hasReferenceName();
}
@Override
public boolean equals(Object that) {
if (this == that) {
return true;
} else if (that instanceof JSType && this.isNominalType()) {
ObjectType thatObj = ObjectType.cast((JSType) that);
if (thatObj != null && thatObj.isNominalType()) {
return getReferenceName().equals(thatObj.getReferenceName());
}
}
return false;
}
/**
* If this is equal to a NamedType object, its hashCode must be equal
* to the hashCode of the NamedType object.
*/
@Override
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>AND: return "bitand";
case Token.EQ: return "eq";
case Token.NE: return "ne";
case Token.LT: return "lt";
case Token.LE: return "le";
case Token.GT: return "gt";
case Token.GE: return "ge";
case Token.LSH: return "lsh";
case Token.RSH: return "rsh";
case Token.URSH: return "ursh";
case Token.ADD: return "add";
case Token.SUB: return "sub";
case Token.MUL: return "mul";
case Token.DIV: return "div";
case Token.MOD: return "mod";
case Token.BITNOT: return "bitnot";
case Token.NEG: return "neg";
case Token.NEW: return "new";
case Token.DELPROP: return "delprop";
case Token.TYPEOF: return "typeof";
case Token.GETPROP: return "getprop";
case Token.SETPROP: return "setprop";
case Token.GETELEM: return "getelem";
case Token.SETELEM: return "setelem";
case Token.CALL: return "call";
case Token.NAME: return "name";
case Token.NUMBER: return "number";
case Token.STRING: return "string";
case Token.NULL: return "null";
case Token.THIS: return "this";
case Token.FALSE: return "false";
case Token.TRUE: return "true";
case Token.SHEQ: return "sheq";
case Token.SHNE: return "shne";
case Token.REGEXP: return "regexp";
case Token.POS: return "pos";
case Token.BINDNAME: return "bindname";
case Token.THROW: return "throw";
case Token.IN: return "in";
case Token.INSTANCEOF: return "instanceof";
case Token.GETVAR: return "getvar";
case Token.SETVAR: return "setvar";
case Token.TRY: return "try";
case Token.TYPEOF
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>/*
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1997-1999
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Bob Jervis
* Google Inc.
*
* Alternatively, the contents of this file may be used under the terms of
* the GNU General Public License Version 2 or later (the "GPL"), in which
* case the provisions of the GPL are applicable instead of those above. If
* you wish to allow use of your version of this file only under the terms of
* the GPL and not to allow others to use your version of this file under the
* MPL, indicate your decision by deleting the provisions above and replacing
* them with the notice and other provisions required by the GPL. If you do
* not delete the provisions above, a recipient may use your version of this
* file under either the MPL or the GPL.
*
* ***** END LICENSE BLOCK ***** */
package com.google.javascript.rhino.jstype;
import static com.google.javascript.rhino.jstype.TernaryValue.FALSE;
import static com.google.javascript.rhino.jstype.TernaryValue.UNKNOWN;
/**
* Number type.
*
*/
public class NumberType extends ValueType {
private static final long serialVersionUID = 1L;
NumberType(JSTypeRegistry registry) {
super(registry);
}
@
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS> constructor;
InstanceObjectType(JSTypeRegistry registry, FunctionType constructor) {
this(registry, constructor, false);
}
InstanceObjectType(JSTypeRegistry registry, FunctionType constructor,
boolean isNativeType) {
super(registry, null, null, isNativeType);
Preconditions.checkNotNull(constructor);
this.constructor = constructor;
}
@Override
public String getReferenceName() {
return getConstructor().getReferenceName();
}
@Override
public boolean hasReferenceName() {
return getConstructor().hasReferenceName();
}
@Override
public ObjectType getImplicitPrototype() {
return getConstructor().getPrototype();
}
@Override
public FunctionType getConstructor() {
return constructor;
}
@Override
boolean defineProperty(String name, JSType type, boolean inferred,
boolean inExterns) {
ObjectType proto = getImplicitPrototype();
if (proto != null && proto.hasOwnDeclaredProperty(name)) {
return false;
}
return super.defineProperty(name, type, inferred, inExterns);
}
@Override
public String toString() {
return constructor.getReferenceName();
}
@Override
boolean isTheObjectType() {
return getConstructor().isNative() && "Object".equals(getReferenceName());
}
@Override
public boolean isInstanceType() {
return true;
}
@Override
public boolean isArrayType() {
return getConstructor().isNative() && "Array".equals(getReferenceName());
}
@Override
public boolean isStringObjectType() {
return getConstructor().isNative() && "String".equals(getReferenceName());
}
@Override
public boolean isBooleanObjectType() {
return getConstructor().isNative() && "Boolean".equals(getReferenceName());
}
@Override
public boolean isNumberObjectType() {
return getConstructor().isNative() && "Number".equals(getReferenceName());
}
@Override
public boolean isDateType() {
return getConstructor().isNative() && "Date".equals(getReferenceName());
}
@Override
public boolean isRegexpType() {
return getConstructor().isNative() && "RegExp".equals(getReferenceName());
}
@Override
public boolean isNominalType() {
return hasReferenceName();
}
@Override
public boolean equals(Object that) {
if
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>1L;
NullType(JSTypeRegistry registry) {
super(registry);
}
@Override
public boolean isNullType() {
return true;
}
@Override
public boolean isNullable() {
return true;
}
@Override
public boolean matchesNumberContext() {
return true;
}
@Override
public boolean matchesObjectContext() {
return false;
}
@Override
public boolean matchesStringContext() {
return true;
}
@Override
public JSType restrictByNotNullOrUndefined() {
return registry.getNativeType(JSTypeNative.NO_TYPE);
}
@Override
public TernaryValue testForEquality(JSType that) {
if (UNKNOWN.equals(super.testForEquality(that))) {
return UNKNOWN;
}
if (that.isNullType() || that.isVoidType()) {
return TRUE;
}
if (that.isUnknownType() || that.isNullable()) {
return UNKNOWN;
}
return FALSE;
}
@Override
public String toString() {
return "null";
}
@Override
public BooleanLiteralSet getPossibleToBooleanOutcomes() {
return BooleanLiteralSet.FALSE;
}
@Override
public <T> T visit(Visitor<T> visitor) {
return visitor.caseNullType();
}
}
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS> ownerFunction;
FunctionPrototypeType(JSTypeRegistry registry, FunctionType ownerFunction,
ObjectType implicitPrototype, boolean isNative) {
super(registry, null /* has no class name */, implicitPrototype,
isNative);
this.ownerFunction = ownerFunction;
}
FunctionPrototypeType(JSTypeRegistry registry, FunctionType ownerFunction,
ObjectType implicitPrototype) {
this(registry, ownerFunction, implicitPrototype, false);
}
@Override
public String getReferenceName() {
if (ownerFunction == null) {
return "{...}.prototype";
} else {
return ownerFunction.getReferenceName() + ".prototype";
}
}
@Override
public boolean hasReferenceName() {
return ownerFunction != null && ownerFunction.hasReferenceName();
}
@Override
public boolean isFunctionPrototypeType() {
return true;
}
public FunctionType getOwnerFunction() {
return ownerFunction;
}
@Override
public Iterable<ObjectType> getCtorImplementedInterfaces() {
return getOwnerFunction().getImplementedInterfaces();
}
// The owner will always be a resolved type, so there's no need to set
// the ownerFunction in resolveInternal.
// (it would lead to infinite loops if we did).
// JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope);
}
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>Type(JSTypeNative.NUMBER_STRING, NUMBER_STRING);
// Native object properties are filled in by externs...
// (String, string)
JSType STRING_VALUE_OR_OBJECT_TYPE =
createUnionType(STRING_OBJECT_TYPE, STRING_TYPE);
registerNativeType(
JSTypeNative.STRING_VALUE_OR_OBJECT_TYPE, STRING_VALUE_OR_OBJECT_TYPE);
// (Number, number)
JSType NUMBER_VALUE_OR_OBJECT_TYPE =
createUnionType(NUMBER_OBJECT_TYPE, NUMBER_TYPE);
registerNativeType(
JSTypeNative.NUMBER_VALUE_OR_OBJECT_TYPE, NUMBER_VALUE_OR_OBJECT_TYPE);
// unknown function type, i.e. (?...) -> ?
FunctionType U2U_FUNCTION_TYPE =
createFunctionType(UNKNOWN_TYPE, true, UNKNOWN_TYPE);
registerNativeType(JSTypeNative.U2U_FUNCTION_TYPE, U2U_FUNCTION_TYPE);
// unknown constructor type, i.e. (?...) -> ? with the NoObject type
// as instance type
FunctionType U2U_CONSTRUCTOR_TYPE =
// This is equivalent to
// createConstructorType(UNKNOWN_TYPE, true, UNKNOWN_TYPE), but,
// in addition, overrides getInstanceType() to return the NoObject type
// instead of a new anonymous object.
new FunctionType(this, "Function", null,
createParametersWithVarArgs(
UNKNOWN_TYPE), UNKNOWN_TYPE, NO_OBJECT_TYPE, null, true, true) {
private static final long serialVersionUID = 1L;
@Override public FunctionType getConstructor() {
return registry.getNativeFunctionType(
JSTypeNative.FUNCTION_FUNCTION_TYPE);
}
};
// The U2U_CONSTRUCTOR is weird, because it's the supertype of its
// own constructor.
registerNativeType(JSTypeNative.U2U_CONSTRUCTOR_TYPE, U2U_CONSTRUCTOR_TYPE);
registerNativeType(
JSTypeNative.FUNCTION_INSTANCE_TYPE, U2U_CONSTRUCTOR_TYPE);
FUNCTION_FUNCTION_TYPE.setInstanceType(U2U_CONSTRUCTOR_TYPE);
U2U_CONSTRUCTOR_TYPE.setImplicitPrototype(FUNCTION_PROTOTYPE);
// least
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>.VOID_TYPE));
register(getNativeType(JSTypeNative.VOID_TYPE), "Undefined");
register(getNativeType(JSTypeNative.VOID_TYPE), "void");
register(getNativeType(JSTypeNative.FUNCTION_INSTANCE_TYPE), "Function");
}
private void register(JSType type) {
register(type, type.toString());
}
private void register(JSType type, String name) {
namesToTypes.put(name, type);
// Add all the namespaces in which this name lives.
while (name.indexOf('.') > 0) {
name = name.substring(0, name.lastIndexOf('.'));
namespaces.add(name);
}
}
private void registerNativeType(JSTypeNative typeId, JSType type) {
nativeTypes[typeId.ordinal()] = type;
}
/**
* Tells the type system that {@code owner} may have a property named
* {@code propertyName}. This allows the registry to keep track of what
* types a property is defined upon.
*
* This is NOT the same as saying that {@code owner} must have a property
* named type. ObjectType#hasProperty attempts to minimize false positives
* ("if we're not sure, then don't type check this property"). The type
* registry, on the other hand, should attempt to minimize false negatives
* ("if this property is assigned anywhere in the program, it must
* show up in the type registry").
*/
public void registerPropertyOnType(String propertyName, ObjectType owner) {
Set<ObjectType> typeSet = typesIndexedByProperty.get(propertyName);
if (typeSet == null) {
typesIndexedByProperty.put(propertyName, typeSet = Sets.newHashSet());
}
greatestSubtypeByProperty.remove(propertyName);
typeSet.add(owner);
}
/**
* Gets the greatest subtype of the {@code type} that has a property
* {@code propertyName} defined on it.
*/
public JSType getGreatestSubtypeWithProperty(
JSType type, String propertyName) {
if (greatestSubtypeByProperty.containsKey(propertyName)) {
return greatestSubtypeByProperty.get(propertyName)
.getGreatestSubtype(type);
}
if (typesIndexedByProperty.containsKey(propertyName)) {
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>io.Serializable;
import java.util.Comparator;
import java.util.List;
/**
* Represents JavaScript value types.<p>
*
* Types are split into two separate families: value types and object types.
*
* A special {@link UnknownType} exists to represent a wildcard type on which
* no information can be gathered. In particular, it can assign to everyone,
* is a subtype of everyone (and everyone is a subtype of it).<p>
*
* If you remove the {@link UnknownType}, the set of types in the type system
* forms a lattice with the {@link #isSubtype} relation defining the partial
* order of types. All types are united at the top of the lattice by the
* {@link AllType} and at the bottom by the {@link NoType}.<p>
*
*
*
*/
public abstract class JSType implements Serializable {
private static final long serialVersionUID = 1L;
private boolean resolved = false;
private JSType resolveResult = null;
public static final String UNKNOWN_NAME =
"Unknown class name";
public static final String NOT_A_CLASS =
"Not declared as a constructor";
public static final String NOT_A_TYPE =
"Not declared as a type name";
public static final String EMPTY_TYPE_COMPONENT =
"Named type with empty name component";
/**
* Total ordering on types based on their textual representation.
* This is used to have a deterministic output of the toString
* method of the union type since this output is used in tests.
*/
static final Comparator<JSType> ALPHA = new Comparator<JSType>() {
public int compare(JSType t1, JSType t2) {
return t1.toString().compareTo(t2.toString());
}
};
// A flag set on enum definition tree nodes
public static final int ENUMDECL = 1;
public static final int NOT_ENUMDECL = 0;
final JSTypeRegistry registry;
JSType(JSTypeRegistry registry) {
this.registry = registry;
}
/**
* Utility method for less verbose code.
*/
JSType getNativeType(JSTypeNative typeId) {
return registry.getNativeType(typeId);
}
/**
* Gets the docInfo
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>TestForShallowEqualityWith(JSType that) {
return this.isSubtype(that) || that.isSubtype(this);
}
/**
* Tests whether this type is nullable.
*/
public boolean isNullable() {
return this.isSubtype(getNativeType(JSTypeNative.NULL_TYPE));
}
/**
* Gets the least supertype of {@code this} and {@code that}.
* The least supertype is the join (∨) or supremum of both types in the
* type lattice.<p>
* Examples:
* <ul>
* <li>{@code number ∨ *} = {@code *}</li>
* <li>{@code number ∨ Object} = {@code (number, Object)}</li>
* <li>{@code Number ∨ Object} = {@code Object}</li>
* </ul>
* @return {@code this ∨ that}
*/
public JSType getLeastSupertype(JSType that) {
if (that.isUnionType()) {
// Union types have their own implementation of getLeastSupertype.
return that.getLeastSupertype(this);
}
return getLeastSupertype(this, that);
}
/**
* A generic implementation meant to be used as a helper for common
* getLeastSupertype implementations.
*/
static JSType getLeastSupertype(JSType thisType, JSType thatType) {
if (thatType.isEmptyType() || thatType.isAllType()) {
// Defer to the implementations of the end lattice elements when
// possible.
return thatType.getLeastSupertype(thisType);
}
return thisType.registry.createUnionType(thisType, thatType);
}
/**
* Gets the greatest subtype of {@code this} and {@code that}.
* The greatest subtype is the meet (∧) or infimum of both types in the
* type lattice.<p>
* Examples
* <ul>
* <li>{@code Number ∧ Any} = {@code Any}</li>
* <li>{@code number ∧ Object} = {@code Any}</li>
* <li>{@code Number
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS> (thatType.isUnknownType()) {
return true;
}
// equality
if (thisType.equals(thatType)) {
return true;
}
// all type
if (thatType.isAllType()) {
return true;
}
// unions
if (thatType instanceof UnionType) {
UnionType union = (UnionType)thatType;
for (JSType element : union.alternates) {
if (thisType.isSubtype(element)) {
return true;
}
}
}
// named types
if (thatType instanceof NamedType) {
return thisType.isSubtype(((NamedType)thatType).referencedType);
}
return false;
}
/**
* Visit this type with the given visitor.
* @see com.google.javascript.rhino.jstype.Visitor
* @return the value returned by the visitor
*/
public abstract <T> T visit(Visitor<T> visitor);
/**
* Resolve this type in the given scope.
*
* The returned value must be equal to {@code this}, as defined by
* {@link Object#equals}. It may or may not be the same object. This method
* may modify the internal state of {@code this}, as long as it does
* so in a way that preserves Object equality.
*
* For efficiency, we should only resolve a type once per compilation job.
* For incremental compilations, one compilation job may need the
* artifacts from a previous generation, so we will eventually need
* a generational flag instead of a boolean one.
*/
public final JSType resolve(ErrorReporter t, StaticScope<JSType> scope) {
if (resolved) {
// TODO(nicksantos): Check to see if resolve() looped back on itself.
// Preconditions.checkNotNull(resolveResult);
if (resolveResult == null) {
return registry.getNativeType(JSTypeNative.UNKNOWN_TYPE);
}
return resolveResult;
}
resolved = true;
resolveResult = resolveInternal(t, scope);
return resolveResult;
}
/**
* @see #resolve
*/
abstract JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope);
void setResolvedTypeInternal(JSType type) {
resolveResult = type
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>
*
*/
final class ArrowType extends JSType {
private static final long serialVersionUID = 1L;
final Node parameters;
JSType returnType;
ArrowType(JSTypeRegistry registry, Node parameters,
JSType returnType) {
super(registry);
this.parameters = parameters;
this.returnType = returnType;
}
@Override
public boolean isSubtype(JSType other) {
if (!(other instanceof ArrowType)) {
return false;
}
ArrowType that = (ArrowType) other;
// this.returnType <: that.returnType (covariant)
// If the return type is null, this is equivalent to unknown so we do not
// base our decision on that.
if (this.returnType != null &&
that.returnType != null &&
!this.returnType.isSubtype(that.returnType)) {
return false;
}
// that.paramType[i] <: this.paramType[i] (contravariant)
// TODO(nicksantos): This is incorrect. It should be invariant.
// Follow up with closure team on how to fix this without everyone
// hating on us.
//
// If the parameter list is null, this is equivalent of ?... so we do not
// base our decision on that.
if (this.parameters != null && that.parameters != null) {
Node thisParam = parameters.getFirstChild();
Node thatParam = that.parameters.getFirstChild();
while (thisParam != null && thatParam != null) {
JSType thisParamType = thisParam.getJSType();
if (thisParamType != null) {
JSType thatParamType = thatParam.getJSType();
if (thatParamType == null ||
!thatParamType.isSubtype(thisParamType)) {
return false;
}
}
boolean thisIsVarArgs = thisParam.isVarArgs();
boolean thatIsVarArgs = thatParam.isVarArgs();
// don't advance if we have variable arguments
if (!thisIsVarArgs) {
thisParam = thisParam.getNext();
}
if (!thatIsVarArgs) {
thatParam = thatParam.getNext();
}
// both var_args indicates the end
if (thisIsVarArgs && thatIsVarArgs) {
thisParam = null;
that
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>.JSTypeRegistry;
import com.google.javascript.rhino.jstype.ObjectType;
import com.google.javascript.rhino.jstype.RecordTypeBuilder;
import junit.framework.TestCase;
public abstract class BaseJSTypeTestCase extends TestCase {
protected JSTypeRegistry registry;
protected TestErrorReporter errorReporter;
protected JSType ALL_TYPE;
protected ObjectType NO_OBJECT_TYPE;
protected ObjectType NO_TYPE;
protected JSType ARRAY_FUNCTION_TYPE;
protected ObjectType ARRAY_TYPE;
protected JSType BOOLEAN_OBJECT_FUNCTION_TYPE;
protected ObjectType BOOLEAN_OBJECT_TYPE;
protected JSType BOOLEAN_TYPE;
protected JSType CHECKED_UNKNOWN_TYPE;
protected JSType DATE_FUNCTION_TYPE;
protected ObjectType DATE_TYPE;
protected JSType ERROR_FUNCTION_TYPE;
protected ObjectType ERROR_TYPE;
protected JSType EVAL_ERROR_FUNCTION_TYPE;
protected ObjectType EVAL_ERROR_TYPE;
protected FunctionType FUNCTION_FUNCTION_TYPE;
protected FunctionType FUNCTION_INSTANCE_TYPE;
protected ObjectType FUNCTION_PROTOTYPE;
protected JSType GREATEST_FUNCTION_TYPE;
protected JSType LEAST_FUNCTION_TYPE;
protected JSType MATH_TYPE;
protected JSType NULL_TYPE;
protected JSType NUMBER_OBJECT_FUNCTION_TYPE;
protected ObjectType NUMBER_OBJECT_TYPE;
protected JSType NUMBER_STRING_BOOLEAN;
protected JSType NUMBER_TYPE;
protected FunctionType OBJECT_FUNCTION_TYPE;
protected JSType OBJECT_NUMBER_STRING;
protected JSType OBJECT_NUMBER_STRING_BOOLEAN;
protected JSType OBJECT_PROTOTYPE;
protected ObjectType OBJECT_TYPE;
protected JSType RANGE_ERROR_FUNCTION_TYPE;
protected ObjectType RANGE_ERROR_TYPE;
protected JSType REFERENCE_ERROR_FUNCTION_TYPE;
protected ObjectType REFERENCE_ERROR_TYPE;
protected JSType REGEXP_FUNCTION_TYPE;
protected ObjectType REGEXP_TYPE;
protected JSType STRING_OBJECT_FUNCTION_TYPE;
protected ObjectType STRING_OBJECT_TYPE;
protected JSType STRING_TYPE;
protected JSType SYNTAX_ERROR_FUNCTION_TYPE;
protected ObjectType SYNTAX_ERROR_TYPE;
protected JSType TYPE_ERROR_FUNCTION_TYPE;
protected ObjectType TYPE_ERROR_TYPE;
protected
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS> FunctionType U2U_CONSTRUCTOR_TYPE;
protected FunctionType U2U_FUNCTION_TYPE;
protected ObjectType UNKNOWN_TYPE;
protected JSType URI_ERROR_FUNCTION_TYPE;
protected ObjectType URI_ERROR_TYPE;
protected JSType VOID_TYPE;
protected int NATIVE_PROPERTIES_COUNT;
@Override
protected void setUp() throws Exception {
super.setUp();
errorReporter = new TestErrorReporter(null, null);
registry = new JSTypeRegistry(errorReporter);
initTypes();
}
protected void initTypes() {
ALL_TYPE =
registry.getNativeType(JSTypeNative.ALL_TYPE);
NO_OBJECT_TYPE =
registry.getNativeObjectType(JSTypeNative.NO_OBJECT_TYPE);
NO_TYPE =
registry.getNativeObjectType(JSTypeNative.NO_TYPE);
ARRAY_FUNCTION_TYPE =
registry.getNativeType(JSTypeNative.ARRAY_FUNCTION_TYPE);
ARRAY_TYPE =
registry.getNativeObjectType(JSTypeNative.ARRAY_TYPE);
BOOLEAN_OBJECT_FUNCTION_TYPE =
registry.getNativeType(JSTypeNative.BOOLEAN_OBJECT_FUNCTION_TYPE);
BOOLEAN_OBJECT_TYPE =
registry.getNativeObjectType(JSTypeNative.BOOLEAN_OBJECT_TYPE);
BOOLEAN_TYPE =
registry.getNativeType(JSTypeNative.BOOLEAN_TYPE);
CHECKED_UNKNOWN_TYPE =
registry.getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
DATE_FUNCTION_TYPE =
registry.getNativeType(JSTypeNative.DATE_FUNCTION_TYPE);
DATE_TYPE =
registry.getNativeObjectType(JSTypeNative.DATE_TYPE);
ERROR_FUNCTION_TYPE =
registry.getNativeType(JSTypeNative.ERROR_FUNCTION_TYPE);
ERROR_TYPE =
registry.getNativeObjectType(JSTypeNative.ERROR_TYPE);
EVAL_ERROR_FUNCTION_TYPE =
registry.getNativeType(JSTypeNative.EVAL_ERROR_FUNCTION_TYPE);
EVAL_ERROR_TYPE =
registry.getNativeObjectType(JSTypeNative.EVAL_ERROR_TYPE);
FUNCTION_FUNCTION_TYPE =
registry.getNativeFunctionType(JSTypeNative.FUNCTION_FUNCTION_TYPE);
FUNCTION_INSTANCE_TYPE =
registry.getNativeFunctionType(JS
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>TypeNative.FUNCTION_INSTANCE_TYPE);
FUNCTION_PROTOTYPE =
registry.getNativeObjectType(JSTypeNative.FUNCTION_PROTOTYPE);
GREATEST_FUNCTION_TYPE =
registry.getNativeType(JSTypeNative.GREATEST_FUNCTION_TYPE);
LEAST_FUNCTION_TYPE =
registry.getNativeType(JSTypeNative.LEAST_FUNCTION_TYPE);
NULL_TYPE =
registry.getNativeType(JSTypeNative.NULL_TYPE);
NUMBER_OBJECT_FUNCTION_TYPE =
registry.getNativeType(JSTypeNative.NUMBER_OBJECT_FUNCTION_TYPE);
NUMBER_OBJECT_TYPE =
registry.getNativeObjectType(JSTypeNative.NUMBER_OBJECT_TYPE);
NUMBER_STRING_BOOLEAN =
registry.getNativeType(JSTypeNative.NUMBER_STRING_BOOLEAN);
NUMBER_TYPE =
registry.getNativeType(JSTypeNative.NUMBER_TYPE);
OBJECT_FUNCTION_TYPE =
registry.getNativeFunctionType(JSTypeNative.OBJECT_FUNCTION_TYPE);
OBJECT_NUMBER_STRING =
registry.getNativeType(JSTypeNative.OBJECT_NUMBER_STRING);
OBJECT_NUMBER_STRING_BOOLEAN =
registry.getNativeType(JSTypeNative.OBJECT_NUMBER_STRING_BOOLEAN);
OBJECT_PROTOTYPE =
registry.getNativeType(JSTypeNative.OBJECT_PROTOTYPE);
OBJECT_TYPE =
registry.getNativeObjectType(JSTypeNative.OBJECT_TYPE);
RANGE_ERROR_FUNCTION_TYPE =
registry.getNativeType(JSTypeNative.RANGE_ERROR_FUNCTION_TYPE);
RANGE_ERROR_TYPE =
registry.getNativeObjectType(JSTypeNative.RANGE_ERROR_TYPE);
REFERENCE_ERROR_FUNCTION_TYPE =
registry.getNativeType(JSTypeNative.REFERENCE_ERROR_FUNCTION_TYPE);
REFERENCE_ERROR_TYPE =
registry.getNativeObjectType(JSTypeNative.REFERENCE_ERROR_TYPE);
REGEXP_FUNCTION_TYPE =
registry.getNativeType(JSTypeNative.REGEXP_FUNCTION_TYPE);
REGEXP_TYPE =
registry.getNativeObjectType(JSTypeNative.REGEXP_TYPE);
STRING_OBJECT_FUNCTION_TYPE =
registry.getNativeType(JSTypeNative.STRING_OBJECT_FUNCTION_TYPE);
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS> STRING_OBJECT_TYPE =
registry.getNativeObjectType(JSTypeNative.STRING_OBJECT_TYPE);
STRING_TYPE =
registry.getNativeType(JSTypeNative.STRING_TYPE);
SYNTAX_ERROR_FUNCTION_TYPE =
registry.getNativeType(JSTypeNative.SYNTAX_ERROR_FUNCTION_TYPE);
SYNTAX_ERROR_TYPE =
registry.getNativeObjectType(JSTypeNative.SYNTAX_ERROR_TYPE);
TYPE_ERROR_FUNCTION_TYPE =
registry.getNativeType(JSTypeNative.TYPE_ERROR_FUNCTION_TYPE);
TYPE_ERROR_TYPE =
registry.getNativeObjectType(JSTypeNative.TYPE_ERROR_TYPE);
U2U_CONSTRUCTOR_TYPE =
registry.getNativeFunctionType(JSTypeNative.U2U_CONSTRUCTOR_TYPE);
U2U_FUNCTION_TYPE =
registry.getNativeFunctionType(JSTypeNative.U2U_FUNCTION_TYPE);
UNKNOWN_TYPE =
registry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE);
URI_ERROR_FUNCTION_TYPE =
registry.getNativeType(JSTypeNative.URI_ERROR_FUNCTION_TYPE);
URI_ERROR_TYPE =
registry.getNativeObjectType(JSTypeNative.URI_ERROR_TYPE);
VOID_TYPE =
registry.getNativeType(JSTypeNative.VOID_TYPE);
addNativeProperties(registry);
NATIVE_PROPERTIES_COUNT = OBJECT_TYPE.getPropertiesCount();
}
/** Adds a basic set of properties to the native types. */
public static void addNativeProperties(JSTypeRegistry registry) {
JSType booleanType = registry.getNativeType(JSTypeNative.BOOLEAN_TYPE);
JSType numberType = registry.getNativeType(JSTypeNative.NUMBER_TYPE);
JSType stringType = registry.getNativeType(JSTypeNative.STRING_TYPE);
JSType unknownType = registry.getNativeType(JSTypeNative.UNKNOWN_TYPE);
ObjectType objectType =
registry.getNativeObjectType(JSTypeNative.OBJECT_TYPE);
ObjectType arrayType =
registry.getNativeObjectType(JSTypeNative.ARRAY_TYPE);
ObjectType dateType =
registry.getNativeObjectType(JSTypeNative.DATE_TYPE);
ObjectType regexpType =
registry.getNativeObjectType(JSTypeNative.
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>REGEXP_TYPE);
ObjectType booleanObjectType =
registry.getNativeObjectType(JSTypeNative.BOOLEAN_OBJECT_TYPE);
ObjectType numberObjectType =
registry.getNativeObjectType(JSTypeNative.NUMBER_OBJECT_TYPE);
ObjectType stringObjectType =
registry.getNativeObjectType(JSTypeNative.STRING_OBJECT_TYPE);
ObjectType objectPrototype = registry
.getNativeFunctionType(JSTypeNative.OBJECT_FUNCTION_TYPE)
.getPrototype();
addMethod(registry, objectPrototype, "constructor", objectType);
addMethod(registry, objectPrototype, "toString", stringType);
addMethod(registry, objectPrototype, "toLocaleString", stringType);
addMethod(registry, objectPrototype, "valueOf", unknownType);
addMethod(registry, objectPrototype, "hasOwnProperty", booleanType);
addMethod(registry, objectPrototype, "isPrototypeOf", booleanType);
addMethod(registry, objectPrototype, "propertyIsEnumerable", booleanType);
ObjectType arrayPrototype = registry
.getNativeFunctionType(JSTypeNative.ARRAY_FUNCTION_TYPE)
.getPrototype();
addMethod(registry, arrayPrototype, "constructor", arrayType);
addMethod(registry, arrayPrototype, "toString", stringType);
addMethod(registry, arrayPrototype, "toLocaleString", stringType);
addMethod(registry, arrayPrototype, "concat", arrayType);
addMethod(registry, arrayPrototype, "join", stringType);
addMethod(registry, arrayPrototype, "pop", unknownType);
addMethod(registry, arrayPrototype, "push", numberType);
addMethod(registry, arrayPrototype, "reverse", arrayType);
addMethod(registry, arrayPrototype, "shift", unknownType);
addMethod(registry, arrayPrototype, "slice", arrayType);
addMethod(registry, arrayPrototype, "sort", arrayType);
addMethod(registry, arrayPrototype, "splice", arrayType);
addMethod(registry, arrayPrototype, "unshift", numberType);
arrayType.defineDeclaredProperty("length", numberType, true);
ObjectType booleanPrototype = registry
.getNativeFunctionType(JSTypeNative.BOOLEAN_OBJECT_FUNCTION_TYPE)
.getPrototype();
addMethod(registry, booleanPrototype, "constructor", booleanObjectType);
addMethod(registry, booleanPrototype, "toString", stringType);
addMethod(registry
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>, booleanPrototype, "valueOf", booleanType);
ObjectType datePrototype = registry
.getNativeFunctionType(JSTypeNative.DATE_FUNCTION_TYPE)
.getPrototype();
addMethod(registry, datePrototype, "constructor", dateType);
addMethod(registry, datePrototype, "toString", stringType);
addMethod(registry, datePrototype, "toDateString", stringType);
addMethod(registry, datePrototype, "toTimeString", stringType);
addMethod(registry, datePrototype, "toLocaleString", stringType);
addMethod(registry, datePrototype, "toLocaleDateString", stringType);
addMethod(registry, datePrototype, "toLocaleTimeString", stringType);
addMethod(registry, datePrototype, "valueOf", numberType);
addMethod(registry, datePrototype, "getTime", numberType);
addMethod(registry, datePrototype, "getFullYear", numberType);
addMethod(registry, datePrototype, "getUTCFullYear", numberType);
addMethod(registry, datePrototype, "getMonth", numberType);
addMethod(registry, datePrototype, "getUTCMonth", numberType);
addMethod(registry, datePrototype, "getDate", numberType);
addMethod(registry, datePrototype, "getUTCDate", numberType);
addMethod(registry, datePrototype, "getDay", numberType);
addMethod(registry, datePrototype, "getUTCDay", numberType);
addMethod(registry, datePrototype, "getHours", numberType);
addMethod(registry, datePrototype, "getUTCHours", numberType);
addMethod(registry, datePrototype, "getMinutes", numberType);
addMethod(registry, datePrototype, "getUTCMinutes", numberType);
addMethod(registry, datePrototype, "getSeconds", numberType);
addMethod(registry, datePrototype, "getUTCSeconds", numberType);
addMethod(registry, datePrototype, "getMilliseconds", numberType);
addMethod(registry, datePrototype, "getUTCMilliseconds", numberType);
addMethod(registry, datePrototype, "getTimezoneOffset", numberType);
addMethod(registry, datePrototype, "setTime", numberType);
addMethod(registry, datePrototype, "setMilliseconds", numberType);
addMethod(registry, datePrototype, "setUTCMilliseconds", number
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>Type);
addMethod(registry, datePrototype, "setSeconds", numberType);
addMethod(registry, datePrototype, "setUTCSeconds", numberType);
addMethod(registry, datePrototype, "setMinutes", numberType);
addMethod(registry, datePrototype, "setUTCMinutes", numberType);
addMethod(registry, datePrototype, "setHours", numberType);
addMethod(registry, datePrototype, "setUTCHours", numberType);
addMethod(registry, datePrototype, "setDate", numberType);
addMethod(registry, datePrototype, "setUTCDate", numberType);
addMethod(registry, datePrototype, "setMonth", numberType);
addMethod(registry, datePrototype, "setUTCMonth", numberType);
addMethod(registry, datePrototype, "setFullYear", numberType);
addMethod(registry, datePrototype, "setUTCFullYear", numberType);
addMethod(registry, datePrototype, "toUTCString", stringType);
addMethod(registry, datePrototype, "toGMTString", stringType);
ObjectType numberPrototype = registry
.getNativeFunctionType(JSTypeNative.NUMBER_OBJECT_FUNCTION_TYPE)
.getPrototype();
addMethod(registry, numberPrototype, "constructor", numberObjectType);
addMethod(registry, numberPrototype, "toString", stringType);
addMethod(registry, numberPrototype, "toLocaleString", stringType);
addMethod(registry, numberPrototype, "valueOf", numberType);
addMethod(registry, numberPrototype, "toFixed", stringType);
addMethod(registry, numberPrototype, "toExponential", stringType);
addMethod(registry, numberPrototype, "toPrecision", stringType);
ObjectType regexpPrototype = registry
.getNativeFunctionType(JSTypeNative.REGEXP_FUNCTION_TYPE)
.getPrototype();
addMethod(registry, regexpPrototype, "constructor", regexpType);
addMethod(registry, regexpPrototype, "exec",
registry.createNullableType(arrayType));
addMethod(registry, regexpPrototype, "test", booleanType);
addMethod(registry, regexpPrototype, "toString", stringType);
regexpType.defineDeclaredProperty("source", stringType, true);
regexpType.defineDeclaredProperty("global", booleanType, true);
regexpType.defineDeclaredProperty("
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>ignoreCase", booleanType, true);
regexpType.defineDeclaredProperty("multiline", booleanType, true);
regexpType.defineDeclaredProperty("lastIndex", numberType, true);
ObjectType stringPrototype = registry
.getNativeFunctionType(JSTypeNative.STRING_OBJECT_FUNCTION_TYPE)
.getPrototype();
addMethod(registry, stringPrototype, "constructor", stringObjectType);
addMethod(registry, stringPrototype, "toString", stringType);
addMethod(registry, stringPrototype, "valueOf", stringType);
addMethod(registry, stringPrototype, "charAt", stringType);
addMethod(registry, stringPrototype, "charCodeAt", numberType);
addMethod(registry, stringPrototype, "concat", stringType);
addMethod(registry, stringPrototype, "indexOf", numberType);
addMethod(registry, stringPrototype, "lastIndexOf", numberType);
addMethod(registry, stringPrototype, "localeCompare", numberType);
addMethod(registry, stringPrototype, "match",
registry.createNullableType(arrayType));
addMethod(registry, stringPrototype, "replace", stringType);
addMethod(registry, stringPrototype, "search", numberType);
addMethod(registry, stringPrototype, "slice", stringType);
addMethod(registry, stringPrototype, "split", arrayType);
addMethod(registry, stringPrototype, "substring", stringType);
addMethod(registry, stringPrototype, "toLowerCase", stringType);
addMethod(registry, stringPrototype, "toLocaleLowerCase", stringType);
addMethod(registry, stringPrototype, "toUpperCase", stringType);
addMethod(registry, stringPrototype, "toLocaleUpperCase", stringType);
stringObjectType.defineDeclaredProperty("length", numberType, true);
}
private static void addMethod(
JSTypeRegistry registry, ObjectType receivingType, String methodName,
JSType returnType) {
receivingType.defineDeclaredProperty(methodName,
new FunctionType(registry, null, null, null, returnType), true);
}
protected JSType createUnionType(JSType... variants) {
return registry.createUnionType(variants);
}
protected RecordTypeBuilder createRecordTypeBuilder() {
return new RecordTypeBuilder(registry);
}
protected JSType createNullableType(JSType type) {
return registry.createNullableType(type);
}
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>
protected JSType createOptionalType(JSType type) {
return registry.createOptionalType(type);
}
/**
* Asserts that a Node representing a type expression resolves to the
* correct {@code JSType}.
*/
protected void assertTypeEquals(JSType expected, Node actual) {
assertTypeEquals(expected, new JSTypeExpression(actual, "", registry));
}
/**
* Asserts that a a type expression resolves to the correct {@code JSType}.
*/
protected void assertTypeEquals(JSType expected, JSTypeExpression actual) {
assertEquals(expected, resolve(actual));
}
/**
* Resolves a type expression, expecting the given warnings.
*/
protected JSType resolve(JSTypeExpression n, String... warnings) {
errorReporter.setWarnings(warnings);
return n.evaluate(null);
}
/**
* A definition of all extern types. This should be kept in sync with
* javascript/externs/es3.js. This is used to check that the builtin types
* declared in {@link JSTypeRegistry} have the same type as that in the
* externs. It can also be used for any tests that want to use builtin types
* in their externs.
*/
public static final String ALL_NATIVE_EXTERN_TYPES =
"/**\n"
+ " * @constructor\n"
+ " * @param {*} opt_value\n"
+ " */\n"
+ "function Object(opt_value) {}\n"
+ "\n"
+ "/**\n"
+ " * @constructor\n"
+ " * @extends {Object}\n"
+ " * @param {*} var_args\n"
+ " */\n"
+ "\n"
+ "function Function(var_args) {}\n"
+ "/**\n"
+ " * @constructor\n"
+ " * @extends {Object}\n"
+ " * @param {*} var_args\n"
+ " * @return {!Array}\n"
+ " */\n"
+ "function Array(var_args) {}\n"
+ "\n"
+ "/**\n"
+ " * @constructor\n"
+ " * @param {*} opt_value\n"
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>
* @param name the function's name or {@code null} to indicate that the
* function is anonymous.
* @param source the node defining this function. Its type
* ({@link Node#getType()}) must be {@link Token#FUNCTION}.
* @param parameters the function's parameters or {@code null}
* to indicate that the parameter types are unknown.
* @param returnType the function's return type or {@code null} to indicate
* that the return type is unknown.
*/
@VisibleForTesting
public FunctionType(JSTypeRegistry registry, String name, Node source,
Node parameters, JSType returnType) {
this(registry, name, source, parameters, returnType, null, null, false,
false);
}
/**
* Creates a function type.
* @param registry the owner registry for this type
* @param name the function's name or {@code null} to indicate that the
* function is anonymous.
* @param source the node defining this function. Its type
* ({@link Node#getType()}) must be {@link Token#FUNCTION}.
* @param parameters the function's parameters or {@code null}
* to indicate that the parameter types are unknown.
* @param returnType the function's return type or {@code null} to indicate
* that the return type is unknown.
* @param typeOfThis The type of {@code this} in non-constructors. May be
* {@code null} to indicate that the type of {@code this} is unknown.
*/
public FunctionType(JSTypeRegistry registry, String name, Node source,
Node parameters, JSType returnType, ObjectType typeOfThis) {
this(registry, name, source, parameters, returnType, typeOfThis,
null, false, false);
}
/**
* Creates a function type.
* @param registry the owner registry for this type
* @param name the function's name or {@code null} to indicate that the
* function is anonymous.
* @param source the node defining this function. Its type
* ({@link Node#getType()}) must be {@link Token#FUNCTION}.
* @param parameters the function's parameters or {@code null}
* to indicate that the parameter types are unknown.
* @param returnType the function's return type or {@code
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS> null} to indicate
* that the return type is unknown.
* @param typeOfThis The type of {@code this} in non-constructors. May be
* {@code null} to indicate that the type of {@code this} is unknown.
* @param templateTypeName The template type name or {@code null}.
*/
public FunctionType(JSTypeRegistry registry, String name, Node source,
Node parameters, JSType returnType, ObjectType typeOfThis,
String templateTypeName) {
this(registry, name, source, parameters, returnType, typeOfThis,
templateTypeName, false, false);
}
/** Creates an instance for a function that might be a constructor. */
FunctionType(JSTypeRegistry registry, String name, Node source,
Node parameters, JSType returnType, ObjectType typeOfThis,
String templateTypeName, boolean isConstructor, boolean nativeType) {
super(registry, name,
registry.getNativeObjectType(JSTypeNative.FUNCTION_INSTANCE_TYPE),
nativeType);
Preconditions.checkArgument(source == null ||
Token.FUNCTION == source.getType());
this.source = source;
this.kind = isConstructor ? Kind.CONSTRUCTOR : Kind.ORDINARY;
if (isConstructor) {
this.typeOfThis = typeOfThis != null && typeOfThis.isNoObjectType() ?
typeOfThis : new InstanceObjectType(registry, this, nativeType);
} else {
this.typeOfThis = typeOfThis != null ?
typeOfThis :
registry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE);
}
// The call type should be set up last because we are calling getReturnType,
// which may be overloaded and depend on other properties being set.
this.call = new ArrowType(registry, parameters,
(returnType == null ? getReturnType() : returnType));
this.templateTypeName = templateTypeName;
}
/** Creates an instance for a function that is an interface. */
FunctionType(JSTypeRegistry registry, String name, Node source) {
super(registry, name,
registry.getNativeObjectType(JSTypeNative.FUNCTION_INSTANCE_TYPE));
Preconditions.checkArgument(source == null ||
Token.FUNCTION == source.getType());
Preconditions.checkArgument(name != null);
this.source = source;
this.call = null;
this
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>.kind = Kind.INTERFACE;
this.typeOfThis = new InstanceObjectType(registry, this);
}
@Override
public boolean isInstanceType() {
// The universal constructor is its own instance, bizarrely.
return equals(registry.getNativeType(U2U_CONSTRUCTOR_TYPE));
}
@Override
public boolean isConstructor() {
return kind == Kind.CONSTRUCTOR;
}
@Override
public boolean isInterface() {
return kind == Kind.INTERFACE;
}
@Override
public boolean isOrdinaryFunction() {
return kind == Kind.ORDINARY;
}
@Override
public boolean isFunctionType() {
return true;
}
@Override
public boolean canBeCalled() {
return true;
}
public Iterable<Node> getParameters() {
Node n = getParametersNode();
if (n != null) {
return n.children();
} else {
return Collections.emptySet();
}
}
/** Gets an LP node that contains all params. May be null. */
public Node getParametersNode() {
return call == null ? null : call.parameters;
}
/** Gets the minimum number of arguments that this function requires. */
public int getMinArguments() {
// NOTE(nicksantos): There are some native functions that have optional
// parameters before required parameters. This algorithm finds the position
// of the last required parameter.
int i = 0;
int min = 0;
for (Node n : getParameters()) {
i++;
if (!n.isOptionalArg() && !n.isVarArgs()) {
min = i;
}
}
return min;
}
/**
* Gets the maximum number of arguments that this function requires,
* or Integer.MAX_VALUE if this is a variable argument function.
*/
public int getMaxArguments() {
Node params = getParametersNode();
if (params != null) {
Node lastParam = params.getLastChild();
if (lastParam == null || !lastParam.isVarArgs()) {
return params.getChildCount();
}
}
return Integer.MAX_VALUE;
}
public JSType getReturnType() {
return call == null ? null : call.returnType;
}
/**
* Gets the {@code prototype}
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS> property of this function type. This is
* equivalent to {@code (ObjectType) getPropertyType("prototype")}.
*/
public FunctionPrototypeType getPrototype() {
// lazy initialization of the prototype field
if (prototype == null) {
setPrototype(new FunctionPrototypeType(registry, this, null));
}
return prototype;
}
/**
* Sets the prototype, creating the prototype object from the given
* base type.
* @param baseType The base type.
*/
public void setPrototypeBasedOn(ObjectType baseType) {
if (prototype == null) {
setPrototype(
new FunctionPrototypeType(
registry, this, baseType, isNativeObjectType()));
} else {
prototype.setImplicitPrototype(baseType);
}
}
/**
* Sets the prototype.
* @param prototype the prototype. If this value is {@code null} it will
* silently be discarded.
*/
public boolean setPrototype(FunctionPrototypeType prototype) {
if (prototype == null) {
return false;
}
// getInstanceType fails if the function is not a constructor
if (isConstructor() && prototype == getInstanceType()) {
return false;
}
this.prototype = prototype;
if (isConstructor() || isInterface()) {
FunctionType superClass = getSuperClassConstructor();
if (superClass != null) {
superClass.addSubType(this);
}
}
return true;
}
/**
* Returns all interfaces implemented by a class or its superclass and any
* superclasses for any of those interfaces. If this is called before all
* types are resolved, it may return an incomplete set.
*/
public Iterable<ObjectType> getAllImplementedInterfaces() {
Set<ObjectType> interfaces = Sets.newHashSet();
for (ObjectType type : getImplementedInterfaces()) {
addRelatedInterfaces(type, interfaces);
}
return interfaces;
}
private void addRelatedInterfaces(ObjectType instance, Set<ObjectType> set) {
FunctionType constructor = instance.getConstructor();
if (constructor != null) {
if (!constructor.isInterface()) {
return;
}
set.add(instance);
if (constructor.getSuperClassConstructor() != null) {
addRelatedInterfaces(
constructor.getSuperClassConstructor().getInstanceType(), set);
}
}
}
/** Returns interfaces
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS> implemented directly by a class or its superclass. */
public Iterable<ObjectType> getImplementedInterfaces() {
FunctionType superCtor = isConstructor() ?
getSuperClassConstructor() : null;
if (superCtor == null) {
return implementedInterfaces;
} else {
return Iterables.concat(
implementedInterfaces, superCtor.getImplementedInterfaces());
}
}
public void setImplementedInterfaces(List<ObjectType> implementedInterfaces) {
// Records this type for each implemented interface.
for (ObjectType type : implementedInterfaces) {
registry.registerTypeImplementingInterface(this, type);
}
this.implementedInterfaces = ImmutableList.copyOf(implementedInterfaces);
}
@Override
public boolean hasProperty(String name) {
return super.hasProperty(name) || "prototype".equals(name);
}
@Override
public boolean hasOwnProperty(String name) {
return super.hasOwnProperty(name) || "prototype".equals(name);
}
@Override
public JSType getPropertyType(String name) {
if ("prototype".equals(name)) {
return getPrototype();
} else {
if (!hasOwnProperty(name)) {
if ("call".equals(name)) {
// Define the "call" function lazily.
Node params = getParametersNode();
if (params == null) {
// If there's no params array, don't do any type-checking
// in this CALL function.
defineDeclaredProperty(name,
new FunctionType(registry, null, null,
null, getReturnType()),
false);
} else {
params = params.cloneTree();
Node thisTypeNode = Node.newString(Token.NAME, "thisType");
thisTypeNode.setJSType(
registry.createOptionalNullableType(getTypeOfThis()));
params.addChildToFront(thisTypeNode);
thisTypeNode.setOptionalArg(true);
defineDeclaredProperty(name,
new FunctionType(registry, null, null,
params, getReturnType()),
false);
}
} else if ("apply".equals(name)) {
// Define the "apply" function lazily.
FunctionParamBuilder builder = new FunctionParamBuilder(registry);
// Ecma-262 says that apply's second argument must be an Array
// or an arguments object. We don't model the arguments object
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>,
// so let's just be forgiving for now.
// TODO(nicksantos): Model the Arguments object.
builder.addOptionalParams(
registry.createNullableType(getTypeOfThis()),
registry.createNullableType(
registry.getNativeType(JSTypeNative.OBJECT_TYPE)));
defineDeclaredProperty(name,
new FunctionType(registry, null, null,
builder.build(), getReturnType()),
false);
}
}
return super.getPropertyType(name);
}
}
@Override
boolean defineProperty(String name, JSType type,
boolean inferred, boolean inExterns) {
if ("prototype".equals(name)) {
ObjectType objType = type.toObjectType();
if (objType != null) {
if (objType.equals(prototype)) {
return true;
}
return setPrototype(
new FunctionPrototypeType(
registry, this, objType, isNativeObjectType()));
} else {
return false;
}
}
return super.defineProperty(name, type, inferred, inExterns);
}
@Override
public boolean isPropertyTypeInferred(String property) {
return "prototype".equals(property) ||
super.isPropertyTypeInferred(property);
}
@Override
public JSType getLeastSupertype(JSType that) {
// NOTE(nicksantos): When we remove the unknown type, the function types
// form a lattice with the universal constructor at the top of the lattice,
// and the NoObject type at the bottom of the lattice.
//
// When we introduce the unknown type, it's much more difficult to make
// heads or tails of the partial ordering of types, because there's no
// clear hierarchy between the different components (parameter types and
// return types) in the ArrowType.
//
// Rather than make the situation more complicated by introducing new
// types (like unions of functions), we just fallback on the simpler
// approach of using the universal constructor and the AnyObject as
// the supremum and infinum of all function types.
if (isFunctionType() && that.isFunctionType()) {
if (equals(that)) {
return this;
}
JSType functionInstance = registry.getNativeType(
JSTypeNative.FUNCTION_INSTANCE_TYPE
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>);
if (functionInstance.equals(that)) {
return that;
} else if (functionInstance.equals(this)) {
return this;
}
return registry.getNativeType(JSTypeNative.U2U_CONSTRUCTOR_TYPE);
}
return super.getLeastSupertype(that);
}
@Override
public JSType getGreatestSubtype(JSType that) {
if (isFunctionType() && that.isFunctionType()) {
if (equals(that)) {
return this;
}
JSType functionInstance = registry.getNativeType(
JSTypeNative.FUNCTION_INSTANCE_TYPE);
if (functionInstance.equals(that)) {
return this;
} else if (functionInstance.equals(this)) {
return that;
}
return registry.getNativeType(JSTypeNative.NO_OBJECT_TYPE);
}
return super.getGreatestSubtype(that);
}
/**
* Given a constructor or an interface type, get its superclass constructor
* or {@code null} if none exists.
*/
public FunctionType getSuperClassConstructor() {
Preconditions.checkArgument(isConstructor() || isInterface());
ObjectType maybeSuperInstanceType = getPrototype().getImplicitPrototype();
if (maybeSuperInstanceType == null) {
return null;
}
return maybeSuperInstanceType.getConstructor();
}
/**
* Given a constructor or an interface type, find out whether the unknown
* type is a supertype of the current type.
*/
public boolean hasUnknownSupertype() {
Preconditions.checkArgument(isConstructor() || isInterface());
Preconditions.checkArgument(!this.isUnknownType());
// Potential infinite loop if our type system messes up or someone defines
// a bad type. Otherwise the loop should always end.
FunctionType ctor = this;
while (true) {
ObjectType maybeSuperInstanceType =
ctor.getPrototype().getImplicitPrototype();
if (maybeSuperInstanceType == null) {
return false;
}
if (maybeSuperInstanceType.isUnknownType()) {
return true;
}
ctor = maybeSuperInstanceType.getConstructor();
if (ctor == null) {
return false;
}
Preconditions.checkState(ctor.isConstructor() || ctor.isInterface());
}
}
/**
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS> * Given a constructor or an interface type and a property, finds the
* top-most superclass that has the property defined (including this
* constructor).
*/
public JSType getTopMostDefiningType(String propertyName) {
Preconditions.checkState(isConstructor() || isInterface());
Preconditions.checkArgument(getPrototype().hasProperty(propertyName));
FunctionType ctor = this;
JSType topInstanceType;
do {
topInstanceType = ctor.getInstanceType();
ctor = ctor.getSuperClassConstructor();
} while (ctor != null && ctor.getPrototype().hasProperty(propertyName));
return topInstanceType;
}
/**
* Two function types are equal if their signatures match. Since they don't
* have signatures, two interfaces are equal if their names match.
*/
@Override
public boolean equals(Object otherType) {
if (!(otherType instanceof FunctionType)) {
return false;
}
FunctionType that = (FunctionType) otherType;
if (!that.isFunctionType()) {
return false;
}
if (this.isConstructor()) {
if (that.isConstructor()) {
return this == that;
}
return false;
}
if (this.isInterface()) {
if (that.isInterface()) {
return this.getReferenceName().equals(that.getReferenceName());
}
return false;
}
if (that.isInterface()) {
return false;
}
return this.typeOfThis.equals(that.typeOfThis) &&
this.call.equals(that.call);
}
@Override
public int hashCode() {
return isInterface() ? getReferenceName().hashCode() : call.hashCode();
}
public boolean hasEqualCallType(FunctionType otherType) {
return this.call.equals(otherType.call);
}
/**
* Informally, a function is represented by
* {@code function (params): returnType} where the {@code params} is a comma
* separated list of types, the first one being a special
* {@code this:T} if the function expects a known type for {@code this}.
*/
@Override
public String toString() {
if (this == registry.getNativeType(JSTypeNative.FUNCTION_INSTANCE_TYPE)) {
return "Function";
}
StringBuilder b =
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS> new StringBuilder(32);
b.append("function (");
int paramNum = (call == null || call.parameters == null) ?
0 : call.parameters.getChildCount();
boolean hasKnownTypeOfThis = !typeOfThis.isUnknownType();
if (hasKnownTypeOfThis) {
b.append("this:");
b.append(typeOfThis.toString());
}
if (paramNum > 0) {
if (hasKnownTypeOfThis) {
b.append(", ");
}
Node p = call.parameters.getFirstChild();
if (p.isVarArgs()) {
appendVarArgsString(b, p.getJSType());
} else {
b.append(p.getJSType().toString());
}
p = p.getNext();
while (p != null) {
b.append(", ");
if (p.isVarArgs()) {
appendVarArgsString(b, p.getJSType());
} else {
b.append(p.getJSType().toString());
}
p = p.getNext();
}
}
b.append(")");
if (call != null && call.returnType != null) {
b.append(": ");
b.append(call.returnType);
}
return b.toString();
}
/** Gets the string representation of a var args param. */
private void appendVarArgsString(StringBuilder builder, JSType paramType) {
if (paramType.isUnionType()) {
// Remove the optionalness from the var arg.
paramType = ((UnionType) paramType).getRestrictedUnion(
registry.getNativeType(JSTypeNative.VOID_TYPE));
}
builder.append("...[").append(paramType.toString()).append("]");
}
/**
* A function is a subtype of another if their call methods are related via
* subtyping and {@code this} is a subtype of {@code that} with regard to
* the prototype chain.
*/
@Override
public boolean isSubtype(JSType that) {
if (this.equals(that)) {
return true;
}
if (that.isFunctionType()) {
if (((FunctionType) that).isInterface()) {
// Any function can be assigned to an interface function.
return true;
}
if (this
Closure, 103
<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB>
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
private static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
<CHANGES>
<CHANGEE>
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
<FILEE>
<FILEB>
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType = null;
ObjectType objType = ObjectType.cast(type);
while (objType != null && objType.getImplicitPrototype() != objType) {
if (objType.hasOwnProperty(field)) {
foundType = objType;
}
objType = objType.getImplicitPrototype();
}
// If the property does not exist on the referenced type but the original
// type is an object type, see if any subtype has the property.
<CHANGES>
<CHANGEE>
// getGreatestSubtypeWithProperty does not guarantee that the property
// is defined on the returned type, it just indicates that it might be,
// so we have to double check.
<CHANGES>
<CHANGEE>
return foundType;
}
@Override public JSType getInstanceFromPrototype(JSType type) {
if (type.isFunctionPrototypeType()) {
FunctionPrototypeType prototype = (FunctionPrototypeType) type;
FunctionType owner = prototype.getOwnerFunction();
if (owner.isConstructor() || owner.isInterface()) {
return ((FunctionPrototypeType) type).getOwnerFunction()
.getInstanceType();
}
}
return null;<SCANS>.isInterface()) {
// An interface function cannot be assigned to anything.
return false;
}
// If functionA is a subtype of functionB, then their "this" types
// should be contravariant. However, this causes problems because
// of the way we enforce overrides. Because function(this:SubFoo)
// is not a subtype of function(this:Foo), our override check treats
// this as an error. It also screws up out standard method
// for aliasing constructors. Let's punt on all this for now.
// TODO(nicksantos): fix this.
FunctionType other = (FunctionType) that;
return (this.isConstructor() || other.isConstructor() ||
other.typeOfThis.isSubtype(this.typeOfThis) ||
this.typeOfThis.isSubtype(other.typeOfThis)) &&
this.call.isSubtype(other.call);
}
if (that instanceof UnionType) {
UnionType union = (UnionType) that;
for (JSType element : union.alternates) {
if (this.isSubtype(element)) {
return true;
}
}
}
return getNativeType(JSTypeNative.FUNCTION_PROTOTYPE).isSubtype(that);
}
@Override
public <T> T visit(Visitor<T> visitor) {
return visitor.caseFunctionType(this);
}
/**
* Gets the type of instance of this function.
* @throws IllegalStateException if this function is not a constructor
* (see {@link #isConstructor()}).
*/
public ObjectType getInstanceType() {
Preconditions.checkState(hasInstanceType());
return typeOfThis;
}
/** Sets the instance type. This should only be used for special native types. */
void setInstanceType(ObjectType instanceType) {
typeOfThis = instanceType;
}
/**
* Returns whether this function type has an instance type.
*/
public boolean hasInstanceType() {
return isConstructor() || isInterface();
}
/**
* Gets the type of {@code this} in this function.
*/
public ObjectType getTypeOfThis() {
return typeOfThis.isNoObjectType() ?
registry.getNativeObjectType(JSTypeNative.OBJECT_TYPE) : typeOfThis;
}
/**